qrouter-1.3.33/0000755000175000001440000000000012626257405012023 5ustar timusersqrouter-1.3.33/configure.in0000664000175000001440000005647412614667030014352 0ustar timusers#!/bin/sh AC_INIT(VERSION,, eda-dev@opencircuitdesign.com) AC_PREREQ(2.60) AC_CONFIG_SRCDIR([Makefile.in]) # Determine the host and build type. # =========================================================================== AC_CANONICAL_HOST AC_CANONICAL_TARGET PACKAGE=qrouter VERSION=`cat ./VERSION | cut -d. -f1-2` REVISION=`cat ./VERSION | cut -d. -f3` AC_SUBST(VERSION) AC_SUBST(REVISION) AC_ARG_PROGRAM # Required programs # =========================================================================== AC_PROG_CC AC_PROG_CPP AC_ISC_POSIX if test "x$U" != "x"; then AC_MSG_ERROR(Compiler not ANSI compliant) fi AC_PROG_INSTALL AC_PROG_RANLIB AC_CHECK_PROG(AUTOCONF, autoconf, autoconf, :) AC_CHECK_PROG(CP, cp, cp, :) AC_CHECK_PROG(RM, rm, rm, :) AC_LANG_C AC_HEADER_STDC AC_CHECK_FUNCS(setenv putenv) # Linker # ========================================= #------------------------------------------------------------ # AC_PROG_LD - find the path to the GNU or non-GNU linker # (This stuff ripped from libtool) #------------------------------------------------------------ AC_DEFUN([AC_PROG_LD], [AC_ARG_WITH(gnu-ld, [ --with-gnu-ld assume the C compiler uses GNU ld [[default=no]]], test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl dnl ###not for PostgreSQL### AC_REQUIRE([AC_CANONICAL_BUILD])dnl ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by GCC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case "$ac_prog" in # Accept absolute paths. changequote(,)dnl [\\/]* | [A-Za-z]:[\\/]*) re_direlt='/[^/][^/]*/\.\./' changequote([,])dnl # Canonicalize the path of ld ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(ac_cv_path_LD, [if test -z "$LD"; then IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then ac_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then test "$with_gnu_ld" != no && break else test "$with_gnu_ld" != yes && break fi fi done IFS="$ac_save_ifs" else ac_cv_path_LD="$LD" # Let the user override the test with a path. fi]) LD="$ac_cv_path_LD" if test -n "$LD"; then AC_MSG_RESULT($LD) else AC_MSG_RESULT(no) fi test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) AC_PROG_LD_GNU ]) AC_DEFUN([AC_PROG_LD_GNU], [AC_CACHE_CHECK([if the linker ($LD) is GNU ld], ac_cv_prog_gnu_ld, [# I'd rather use --version here, but apparently some GNU ld's only accept -v. if $LD -v 2>&1 &5; then ac_cv_prog_gnu_ld=yes else ac_cv_prog_gnu_ld=no fi]) with_gnu_ld=$ac_cv_prog_gnu_ld ]) AC_PROG_LD dnl Check for va_copy AC_CACHE_CHECK([for va_copy], ac_cv_c_va_copy, AC_TRY_LINK( [#include ], [va_list ap1, ap2; va_copy(ap1,ap2); ], [ac_cv_c_va_copy="yes"], [ac_cv_c_va_copy="no"]) ) if test "$ac_cv_c_va_copy" = "yes" then AC_DEFINE(HAVE_VA_COPY, 1, [Define if we have va_copy]) fi AC_CACHE_CHECK([for __va_copy], ac_cv_c___va_copy, AC_TRY_LINK( [#include ], [va_list ap1, ap2; __va_copy(ap1,ap2); ], [ac_cv_c___va_copy="yes"], [ac_cv_c___va_copy="no"]) ) if test "$ac_cv_c___va_copy" = "yes" then AC_DEFINE(HAVE___VA_COPY, 1, [Define if we have __va_copy]) fi # Options # ========================================= QROUTER_LIB_DIR="share/qrouter" AC_ARG_WITH(libdir, [ --with-libdir=DIR path to qrouter default config files], [ QROUTER_LIB_DIR=$withval ], []) # Interpreter Options # ========================================= qrouter_with_tcl="yes" qrouter_with_tk="yes" qrouter_with_tcl_includes="" qrouter_with_tk_includes="" qrouter_with_tcl_libraries="" qrouter_with_tk_libraries="" usingTcl=1 AC_ARG_WITH(tcl, [ --with-tcl=DIR Find tclConfig.sh in DIR], [ qrouter_with_tcl=$withval if test "$withval" = "no" -o "$withval" = "NO"; then usingTcl= fi ], ) #----------------------------------------------------- # SHDLIB_EXT needs to be defined outside of the # Tcl/Tk environment, otherwise the Makefile # target can't differentiate between qrouter and # qrouter.so #----------------------------------------------------- case $target in *-hpux*) SHDLIB_EXT=".sl" SHDLIB_EXT_ALT=".sl" ;; *cygwin*) SHDLIB_EXT=".dll" SHDLIB_EXT_ALT=".dll.a" ;; *darwin*) SHDLIB_EXT=".dylib" SHDLIB_EXT_ALT=".dylib" ;; *) SHDLIB_EXT=".so" SHDLIB_EXT_ALT=".so" ;; esac dnl ---------------------------------------------------------------- dnl Do our best to find Tcl/Tk. If we can't, then flag a warning dnl and don't set the usingTcl variable. dnl dnl This has been broken up into a number of sections, each of which dnl depends independently on the setting of usingTcl. dnl ---------------------------------------------------------------- AC_ARG_WITH(tk, [ --with-tk=DIR Find tkConfig.sh in DIR], qrouter_with_tk=$withval) AC_ARG_WITH(tclincls, [ --with-tclincls=DIR Find tcl.h in DIR], qrouter_with_tcl_includes=$withval) AC_ARG_WITH(tkincls, [ --with-tkincls=DIR Find tk.h in DIR], qrouter_with_tk_includes=$withval) AC_ARG_WITH(tcllibs, [ --with-tcllibs=DIR Find Tcl library in DIR], qrouter_with_tcl_libraries=$withval) AC_ARG_WITH(tklibs, [ --with-tklibs=DIR Find Tk library in DIR], qrouter_with_tk_libraries=$withval) # ----------------------------------------------------------------------- # Find the Tcl build configuration file "tclConfig.sh" # ----------------------------------------------------------------------- if test $usingTcl ; then TCL_INC_DIR="." TK_INC_DIR="." AC_MSG_CHECKING([for tclConfig.sh]) tcl_config_sh="" if test "$qrouter_with_tcl" = "no" ; then qrouter_with_tcl="" elif test "$qrouter_with_tcl" != "yes" ; then # # Verify that a tclConfig.sh file exists in the directory specified # by --with-tcl. # for dir in \ $qrouter_with_tcl do if test -r "$dir/tclConfig.sh" ; then tcl_config_sh="$dir/tclConfig.sh" break elif test -r "$dir/lib/tclConfig.sh" ; then tcl_config_sh="$dir/lib/tclConfig.sh" break elif test -r "$dir/unix/tclConfig.sh" ; then tcl_config_sh="$dir/unix/tclConfig.sh" break fi done else # # Otherwise, search for Tcl configuration file. # # 1. Search previously named locations. for dir in \ $ac_default_prefix \ $exec_prefix do if test -r "$dir/tclConfig.sh" ; then tcl_config_sh="$dir/tclConfig.sh" break elif test -r "$dir/lib/tclConfig.sh" ; then tcl_config_sh="$dir/lib/tclConfig.sh" break elif test -r "$dir/unix/tclConfig.sh" ; then tcl_config_sh="$dir/unix/tclConfig.sh" break fi done # 2. Search standard locations. if test "x$tcl_config_sh" = "x" ; then for dir in \ `ls -dr /usr/local/tcl/tcl[[7-9]].[[0-9]]* 2>/dev/null` \ /usr/local/tcl \ /usr/local/lib \ /usr/local \ `ls -dr /usr/lib/tcl[[7-9]].[[0-9]]* 2>/dev/null` \ `ls -dr /usr/share/tcltk/tcl[[7-9]].[[0-9]]* 2>/dev/null` \ /sw/lib \ /usr/lib \ /usr/lib64 \ /usr do if test -r "$dir/tclConfig.sh" ; then tcl_config_sh="$dir/tclConfig.sh" break elif test -r "$dir/lib/tclConfig.sh" ; then tcl_config_sh="$dir/lib/tclConfig.sh" break fi done fi fi AC_MSG_RESULT([${tcl_config_sh}]) if test "x$tcl_config_sh" = "x" ; then echo "Can't find Tcl configuration script \"tclConfig.sh\"" echo "Reverting to non-Tcl compilation" usingTcl= fi fi # ----------------------------------------------------------------------- # Find the Tk build configuration file "tkConfig.sh" # ----------------------------------------------------------------------- if test $usingTcl ; then AC_MSG_CHECKING([for tkConfig.sh]) tk_config_sh="" if test "$qrouter_with_tk" != "yes"; then # # Verify that a tkConfig.sh file exists in the directory specified # by --with-tcl or --with-tk. # for dir in \ $qrouter_with_tk \ $qrouter_with_tcl do if test -r "$dir/tkConfig.sh" ; then tk_config_sh="$dir/tkConfig.sh" break elif test -r "$dir/lib/tkConfig.sh" ; then tk_config_sh="$dir/lib/tkConfig.sh" break elif test -r "$dir/unix/tkConfig.sh" ; then tk_config_sh="$dir/unix/tkConfig.sh" break fi done else # # Search for Tk configuration file. # # # 1. Search previously named locations. # for dir in \ $ac_default_prefix \ $exec_prefix do if test -r "$dir/tkConfig.sh" ; then tk_config_sh="$dir/tkConfig.sh" break elif test -r "$dir/lib/tkConfig.sh" ; then tk_config_sh="$dir/lib/tkConfig.sh" break elif test -r "$dir/unix/tkConfig.sh" ; then tk_config_sh="$dir/unix/tkConfig.sh" break fi done # # 2. Search standard locations. # if test "x$tk_config_sh" = "x" ; then for dir in \ `ls -dr /usr/local/tcl/tcl[[7-9]].[[0-9]]* 2>/dev/null` \ `ls -dr /usr/local/tk/tk[[7-9]].[[0-9]]* 2>/dev/null` \ /usr/local/tcl \ /usr/local/lib \ /sw/lib \ /usr/local \ `ls -dr /usr/share/tcltk/tk[[7-9]].[[0-9]]* 2>/dev/null` \ `ls -dr /usr/lib/tcl[[7-9]].[[0-9]]* 2>/dev/null` \ `ls -dr /usr/lib/tk[[7-9]].[[0-9]]* 2>/dev/null` \ ${x_libraries} \ /usr/lib \ /usr/lib64 \ /usr do if test -r "$dir/tkConfig.sh" ; then tk_config_sh="$dir/tkConfig.sh" break elif test -r "$dir/lib/tkConfig.sh" ; then tk_config_sh="$dir/lib/tkConfig.sh" break fi done fi fi AC_MSG_RESULT([${tk_config_sh}]) if test "x$tk_config_sh" = "x" ; then echo "can't find Tk configuration script \"tkConfig.sh\"" echo "Reverting to non-Tcl compilation" usingTcl= fi fi # ----------------------------------------------------------------------- # Source in the Tcl/Tk configuration scripts. # ----------------------------------------------------------------------- if test $usingTcl ; then . $tcl_config_sh . $tk_config_sh if test "$TCL_VERSION" = "7.6" -a "$TK_VERSION" = "4.2" ; then : elif test "$TCL_VERSION" = "7.5" -a "$TK_VERSION" = "4.1" ; then : elif test "$TCL_VERSION" = "$TK_VERSION" ; then : else echo "Mismatched Tcl/Tk versions ($TCL_VERSION != $TK_VERSION)" echo "Reverting to non-Tcl compile" usingTcl= fi fi if test $usingTcl ; then if test "x${qrouter_with_tcl_includes}" != "x" ; then if test -r "${qrouter_with_tcl_includes}/tcl.h" ; then TCL_INC_DIR=${qrouter_with_tcl_includes} else echo "Can't find tcl.h in \"${qrouter_with_tcl_includes}\"" echo "Reverting to non-Tcl compile" usingTcl= fi else for dir in \ ${TCL_PREFIX}/include/tcl${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION} \ ${TCL_PREFIX}/include \ ${TCL_SRC_DIR}/generic \ ${TCL_INC_DIR} do if test -r "$dir/tcl.h" ; then TCL_INC_DIR=$dir break fi done if test "x${TCL_INC_DIR}" = "x" ; then echo "Can't find tcl.h header file" echo "Reverting to non-Tcl compile" usingTcl= fi fi fi if test $usingTcl ; then if test "x${qrouter_with_tk_includes}" != "x" ; then if test -r "${qrouter_with_tk_includes}/tk.h" ; then TK_INC_DIR=${qrouter_with_tk_includes} else echo "Can't find tk.h in \"${qrouter_with_tk_includes}\"" echo "Reverting to non-Tcl compile" usingTcl= fi else for dir in \ ${TK_PREFIX}/include/tk${TK_MAJOR_VERSION}.${TK_MINOR_VERSION} \ ${TK_PREFIX}/include \ ${TK_SRC_DIR}/generic \ ${TK_INC_DIR} \ ${TCL_INC_DIR} do if test -r "$dir/tk.h" ; then TK_INC_DIR=$dir break fi done if test "x${TK_INC_DIR}" = "x" ; then echo "Can't find tk.h header file" echo "Reverting to non-Tcl compile" usingTcl= fi fi fi if test $usingTcl ; then case $target in *-sunos4*|*-*-netbsd|NetBSD-*|FreeBSD-*|OpenBSD-*) TCL_LIB_NAME="tcl${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}" TK_LIB_NAME="tk${TK_MAJOR_VERSION}${TK_MINOR_VERSION}" ;; *) TCL_LIB_NAME="tcl${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}" TK_LIB_NAME="tk${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}" ;; esac loclib=`echo ${TCL_LIB_SPEC} | sed -e 's/.*-L//' -e 's/ .*//'` if test "x${TCL_LIB_SPEC}" = "x" ; then TCL_LIB_SPEC="-l${TCL_LIB_NAME}" fi if test "x${TK_LIB_SPEC}" = "x" ; then TK_LIB_SPEC="-l${TK_LIB_NAME}" fi # Find the version of "wish" that corresponds to TCL_EXEC_PREFIX # We really ought to run "ldd" to confirm that the linked libraries match. AC_MSG_CHECKING([for wish executable]) for dir in \ ${TK_EXEC_PREFIX}/bin \ ${TK_EXEC_PREFIX} do for wishexe in \ wish \ wish${TK_VERSION} \ wish.exe \ wish${TK_VERSION}.exe do if test -r "$dir/$wishexe" ; then WISH_EXE=$dir/$wishexe break fi done if test "x${WISH_EXE}" != "x" ; then break fi done if test "x${WISH_EXE}" = "x" ; then echo "Warning: Can't find executable for \"wish\". You may have to" echo "manually set the value for WISH_EXE in the netgen startup script." AC_MSG_RESULT(no) else AC_MSG_RESULT([${WISH_EXE}]) fi if test "x${qrouter_with_tcl_libraries}" != "x" ; then for libname in \ "${qrouter_with_tcl_libraries}/lib${TCL_LIB_NAME}${SHDLIB_EXT}" \ "${qrouter_with_tcl_libraries}/lib${TCL_LIB_NAME}${SHDLIB_EXT_ALT}" do if test -r "$libname" ; then TCL_LIB_DIR="${qrouter_with_tcl_libraries}" break fi done if test "x${TCL_LIB_DIR}" = "x" ; then echo "Can't find tcl library in \"${qrouter_with_tcl_libraries}\"" echo "Reverting to non-Tcl compile" usingTcl= fi else for libpfix in "lib64" "lib" do libname1="${TCL_EXEC_PREFIX}/${libpfix}/${DEB_HOST_MULTIARCH}/lib${TCL_LIB_NAME}${SHDLIB_EXT}" libname2="${TCL_EXEC_PREFIX}/${libpfix}/${DEB_HOST_MULTIARCH}/lib${TCL_LIB_NAME}${SHDLIB_EXT_ALT}" if test -r "$libname1" -o -r "$libname2" ; then TCL_LIB_DIR="${TCL_EXEC_PREFIX}/${libpfix}" break fi done if test "x${TCL_LIB_DIR}" = "x" ; then echo "Can't find tcl library" echo "Reverting to non-Tcl compile" usingTcl= fi fi fi if test $usingTcl ; then if test "x${qrouter_with_tk_libraries}" != "x" ; then for libname in \ "${qrouter_with_tk_libraries}/lib${TK_LIB_NAME}${SHDLIB_EXT}" \ "${qrouter_with_tk_libraries}/lib${TK_LIB_NAME}${SHDLIB_EXT_ALT}" do if test -r "$libname" ; then TK_LIB_DIR="${qrouter_with_tk_libraries}" break fi done if test "x${TK_LIB_DIR}" = "x" ; then echo "Can't find tk library in \"${qrouter_with_tk_libraries}\"" echo "Reverting to non-Tcl compile" usingTcl= fi else for libpfix in "lib64" "lib" do libname1="${TK_EXEC_PREFIX}/${libpfix}/${DEB_HOST_MULTIARCH}/lib${TK_LIB_NAME}${SHDLIB_EXT}" libname2="${TK_EXEC_PREFIX}/${libpfix}/${DEB_HOST_MULTIARCH}/lib${TK_LIB_NAME}${SHDLIB_EXT_ALT}" if test -r "$libname1" -o -r "$libname2" ; then TK_LIB_DIR="${TK_EXEC_PREFIX}/${libpfix}" break fi done if test "x${TK_LIB_DIR}" = "x" ; then echo "Can't find tk library" echo "Reverting to non-Tcl compile" usingTcl= fi fi fi dnl ---------------------------------------------------- dnl End of Tcl/Tk search dnl ---------------------------------------------------- AC_ARG_ENABLE(memdebug, [ --enable-memdebug enable memory debugging], [ if test "x$qrouter_with_tcl" = "x" ; then LIBS="${LIBS} -lefence" else AC_DEFINE(TCL_MEM_DEBUG) fi ],) dnl Check for X enabled/disabled AC_PATH_XTRA if test "x$no_x" = "x"; then usingX11=1 else echo Cannot find X11---will compile anyway. echo Graphics will be disabled if test $usingTcl ; then echo "Cannot compile TCL version without X11, disabling." usingTcl= fi fi AC_CHECK_LIB(Xt, XtToolkitInitialize,,[ AC_CHECK_LIB(Xt, XtDisplayInitialize,,,-lSM -lICE -lXpm -lX11)]) dnl ---------------------------------------------------------------- dnl Once we're sure what, if any, interpreter is being compiled, dnl set all the appropriate definitions. For Tcl/Tk, override dnl the default install targets: allows compiling tcl version with dnl "make" instead of requiring "make tcl" dnl ---------------------------------------------------------------- if test $usingTcl ; then ALL_TARGET="tcl" INSTALL_TARGET="install-tcl" AC_DEFINE(TCL_QROUTER) else ALL_TARGET="nointerp" INSTALL_TARGET="install-nointerp" programs="$programs qrouter" fi dnl ---------------------------------------------------------------- dnl Define system-specific settings dnl ---------------------------------------------------------------- case $target in *-linux*) AC_DEFINE(LINUX) AC_DEFINE(SYSV) dnl 64-bit support case $target in *x86_64*) CPPFLAGS="$CPPFLAGS -m64 -fPIC" ;; esac ;; *solaris*) AC_DEFINE(SYSV) ;; *irix*) AC_DEFINE(SYSV) AC_DEFINE(IRIX) AC_DEFINE(_BSD_SIGNALS) ;; *sysv*) AC_DEFINE(SYSV) ;; *cygwin*) AC_DEFINE(CYGWIN) AC_DEFINE(i386) ;; *darwin*) if test "$CPP" = "cc -E" ; then CPPFLAGS="$CPPFLAGS -no-cpp-precomp" fi ;; esac # ----------------------------------------------------------------------- # Tcl/Tk configuration # ----------------------------------------------------------------------- if test $usingTcl ; then # ----------------------------------------------------------------------- # # Tk libraries and header files # # ----------------------------------------------------------------------- if test "${TK_INC_DIR}" != "/usr/include" ; then INC_SPECS="${INC_SPECS} -I${TK_INC_DIR}" fi if test "${TK_LIB_DIR}" = "/usr/lib" -o \ "${TK_LIB_DIR}" = "/usr/lib64" ; then LIB_SPECS="${LIB_SPECS} ${TK_LIB_SPEC}" else LIB_SPECS="${LIB_SPECS} -L${TK_LIB_DIR} ${TK_LIB_SPEC}" if test "x${loader_run_path}" = "x" ; then loader_run_path="${TK_LIB_DIR}" else loader_run_path="${TK_LIB_DIR}:${loader_run_path}" fi fi # ----------------------------------------------------------------------- # # Tcl libraries and header files # # Add a header file directory specification only if the Tcl headers reside # in a different directory from Tk's. # ## ----------------------------------------------------------------------- if test "${TCL_INC_DIR}" != "/usr/include" -a \ "${TCL_INC_DIR}" != "${TK_INC_DIR}" ; then INC_SPECS="${INC_SPECS} -I${TCL_INC_DIR}" fi if test "${TCL_LIB_DIR}" = "/usr/lib" -o \ "${TCL_LIB_DIR}" = "/usr/lib64" -o \ "${TCL_LIB_DIR}" = "${TK_LIB_DIR}" ; then LIB_SPECS="${LIB_SPECS} ${TCL_LIB_SPEC}" else LIB_SPECS="${LIB_SPECS} -L${TCL_LIB_DIR} ${TCL_LIB_SPEC}" if test "x${loader_run_path}" = "x" ; then loader_run_path="${TCL_LIB_DIR}" else loader_run_path="${TCL_LIB_DIR}:${loader_run_path}" fi fi #-------------------------------------------------------------------- # # Check if we can generate shared libraries on this system. Set flags # to generate shared libraries for systems that we know about. Start # with the values found in tclConfig.sh, make changes as we know about # the different systems. # #-------------------------------------------------------------------- # Initialize shared library build variables SHLIB_LD="" LDDL_FLAGS="-shared" SHDLIB_EXT=".so" EXTRA_LIB_SPECS="" build_shared="yes" case $target in *-bsdi2*|*-bsdi3*) LD="shlicc" LDDL_FLAGS="-r" EXTRA_LIB_SPECS="-ldl" ;; *darwin*) SHDLIB_EXT=".dylib" LDDL_FLAGS="-dynamiclib -flat_namespace -undefined suppress -noprebind" LDFLAGS="${LDFLAGS} ${LIB_SPECS}" CFLAGS="${CFLAGS} ${X_CFLAGS} ${INC_SPECS} -I/sw/include -fno-common" ;; *cygwin*) SHDLIB_EXT=".dll" AC_DEFINE(USE_DL_IMPORT) LDDL_FLAGS='-shared -Wl,--enable-auto-image-base' if test "x${loader_run_path}" != "x" ; then LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" fi ld_extra_libs=${LIB_SPECS} sub_extra_libs='-L${QROUTERDIR}/qrouter -ltclqrouter' ;; *-bsdi4*) SHLIB_CFLAGS="-export-dynamic -fPIC" LDDL_FLAGS='-shared -Wl,-E -Wl,-soname,$@' ;; *-linux*) LDDL_FLAGS='-shared -Wl,-soname,$@' if test "x${loader_run_path}" != "x" ; then LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" fi LDFLAGS="" EXTRA_LIB_SPECS="-ldl" ;; *-freebsd*) # Not available on all versions: check for include file. SHLIB_CFLAGS="-fpic" LDDL_FLAGS="-shared ${LIB_SPECS}" CFLAGS="${CFLAGS} -l/usr/X11R6/include" ;; *-netbsd*|*-openbsd*) # Not available on all versions: check for include file. AC_CHECK_HEADER(dlfcn.h, test_ok=yes, test_ok=no) if test "$test_ok" = yes; then SHLIB_CFLAGS="-fpic" LDDL_FLAGS="-Bshareable -x ${LIB_SPEC}" fi ;; esac # If we're running gcc, then set SHLIB_CFLAGS flags for compiling # shared libraries for gcc, instead of those of the vendor's compiler. if test "$GCC" = "yes" ; then case $target in *cygwin*) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac fi if test "$with_gnu_ld" = "yes" ; then LDDL_FLAGS="${LDDL_FLAGS} -Wl,--version-script=symbol.map" fi AC_SUBST(SHDLIB_EXT) AC_SUBST(SHLIB_LD) AC_SUBST(LD) AC_SUBST(LDDL_FLAGS) AC_SUBST(SHLIB_LIB_SPECS) AC_SUBST(EXTRA_LIB_SPECS) AC_SUBST(LDFLAGS) AC_SUBST(INC_SPECS) AC_SUBST(LIB_SPECS) AC_SUBST(TCL_LIB_DIR) AC_SUBST(TK_LIB_DIR) AC_SUBST(WISH_EXE) AC_SUBST(X_LIBS) AC_SUBST(X_EXTRA_LIBS) AC_SUBST(X_PRE_LIBS) AC_SUBST(X_CFLAGS) AC_SUBST(SHLIB_CFLAGS) AC_SUBST(LD_RUN_PATH) fi dnl Substitute all variables AC_SUBST(CPPFLAGS) AC_SUBST(CFLAGS) AC_SUBST(STDLIBS) AC_SUBST(ALL_TARGET) AC_SUBST(INSTALL_TARGET) AC_SUBST(QROUTER_LIB_DIR) AC_DEFINE_UNQUOTED(VERSION, "$VERSION") AC_DEFINE_UNQUOTED(REVISION, "$REVISION") AC_OUTPUT(Makefile) qrouter-1.3.33/symbol.map0000644000175000001440000000006712406043443014021 0ustar timusersQROUTER_1.2 { global: Qrouter_Init; local: *; }; qrouter-1.3.33/Makefile.in0000664000175000001440000000654612614667030014101 0ustar timusers# # qrouter Makefile # # Main compiler arguments CFLAGS += @CFLAGS@ CPPFLAGS = @CPPFLAGS@ DEFS = @DEFS@ LIBS = @LIBS@ LDFLAGS += @LDFLAGS@ LDDL_FLAGS = @LDDL_FLAGS@ LD_RUN_PATH = @LD_RUN_PATH@ SHLIB_CFLAGS = @SHLIB_CFLAGS@ LIB_SPECS = @LIB_SPECS@ INC_SPECS = @INC_SPECS@ TCL_LIB_DIR = @TCL_LIB_DIR@ TK_LIB_DIR = @TK_LIB_DIR@ EXTRA_LIB_SPECS = @EXTRA_LIB_SPECS@ INSTALL = @INSTALL@ SHDLIB_EXT = @SHDLIB_EXT@ EXEEXT = @EXEEXT@ X_LIBS = @X_LIBS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ QROUTER_LIB_DIR = @QROUTER_LIB_DIR@ WISH_EXE = @WISH_EXE@ VERSION = @VERSION@ REVISION = @REVISION@ prefix = @prefix@ INSTALL_TARGET := @INSTALL_TARGET@ ALL_TARGET := @ALL_TARGET@ SOURCES = qrouter.c maze.c node.c qconfig.c lef.c def.c OBJECTS := $(patsubst %.c,%.o,$(SOURCES)) SOURCES2 = graphics.c tclqrouter.c tkSimple.c OBJECTS2 := $(patsubst %.c,%.o,$(SOURCES2)) SOURCES3 = qrouterexec.c OBJECTS3 := $(patsubst %.c,%.o,$(SOURCES3)) SOURCES4 = main.c OBJECTS4 := $(patsubst %.c,%.o,$(SOURCES4)) BININSTALL = ${prefix}/bin LIBINSTALL = ${prefix}/${QROUTER_LIB_DIR} EXTRA_DEFS = -DQROUTER_PATH=\"${LIBINSTALL}\" all: $(ALL_TARGET) install: $(INSTALL_TARGET) nointerp: qrouter$(EXEEXT) tcl: qrouter.sh qrouter.tcl qrouter$(SHDLIB_EXT) qrouterexec$(EXEEXT) qrouter.tcl: qrouter.tcl.in sed -e '/LIBDIR/s#LIBDIR#${LIBINSTALL}#' \ -e '/VERSION/s#VERSION#${VERSION}#' \ -e '/REVISION/s#REVISION#${REVISION}#' \ qrouter.tcl.in > $@ qrouter.sh: qrouter.sh.in sed -e '/WISH_EXE/s#WISH_EXE#${WISH_EXE}#' \ -e '/LIBDIR/s#LIBDIR#${LIBINSTALL}#' \ qrouter.sh.in > $@ chmod 0755 $@ qrouter$(EXEEXT): $(OBJECTS) $(OBJECTS4) $(CC) $(LDFLAGS) $(OBJECTS) $(OBJECTS4) -o $@ $(LIBS) -lm qrouter$(SHDLIB_EXT): $(OBJECTS) $(OBJECTS2) $(RM) qrouter$(SHDLIB_EXT) $(CC) ${CFLAGS} ${SHLIB_CFLAGS} -o $@ \ ${LDDL_FLAGS} $(OBJECTS) $(OBJECTS2) \ ${LDFLAGS} -lc ${LIBS} ${X_PRE_LIBS} -lX11 ${X_LIBS} \ ${X_EXTRA_LIBS} ${LIB_SPECS} ${EXTRA_LIB_SPECS} -lm qrouterexec$(EXEEXT): $(OBJECTS3) $(RM) qrouterexec$(EXEEXT) $(CC) ${CFLAGS} ${CPPFLAGS} ${DEFS} ${EXTRA_DEFS} \ ${SOURCES3} ${INC_SPECS} -o $@ ${LIB_SPECS} \ ${LD_RUN_PATH} ${LDFLAGS} ${X_PRE_LIBS} -lX11 ${X_LIBS} \ ${X_EXTRA_LIBS} ${LIBS} ${EXTRA_LIB_SPECS} -lm install-nointerp: @echo "Installing qrouter" $(INSTALL) -d $(DESTDIR)${BININSTALL} $(INSTALL) qrouter $(DESTDIR)${BININSTALL} install-tcl: qrouter.sh qrouter.tcl qrouter$(SHDLIB_EXT) qrouterexec$(EXEEXT) @echo "Installing qrouter" $(INSTALL) -d $(DESTDIR)${BININSTALL} $(INSTALL) -d $(DESTDIR)${LIBINSTALL} $(INSTALL) qrouter.sh $(DESTDIR)${BININSTALL}/qrouter $(INSTALL) qrouter$(SHDLIB_EXT) $(DESTDIR)${LIBINSTALL} $(INSTALL) qrouterexec$(EXEEXT) $(DESTDIR)${LIBINSTALL} $(INSTALL) console.tcl $(DESTDIR)${LIBINSTALL} $(INSTALL) tkcon.tcl $(DESTDIR)${LIBINSTALL} $(INSTALL) qrouter.tcl $(DESTDIR)${LIBINSTALL} uninstall: $(RM) $(DESTDIR)${BININSTALL}/qrouter clean: $(RM) $(OBJECTS) $(RM) $(OBJECTS2) $(RM) $(OBJECTS3) $(RM) $(OBJECTS4) $(RM) qrouterexec$(EXEEXT) $(RM) qrouter$(EXEEXT) $(RM) qrouter$(SHDLIB_EXT) $(RM) qrouter.tcl $(RM) qrouter.sh veryclean: $(RM) $(OBJECTS) $(RM) $(OBJECTS2) $(RM) $(OBJECTS3) $(RM) $(OBJECTS4) $(RM) qrouterexec$(EXEEXT) $(RM) qrouter$(EXEEXT) $(RM) qrouter$(SHDLIB_EXT) $(RM) qrouter.tcl $(RM) qrouter.sh .c.o: $(CC) $(CFLAGS) $(CPPFLAGS) $(SHLIB_CFLAGS) $(DEFS) \ $(EXTRA_DEFS) $(INC_SPECS) -c $< -o $@ qrouter-1.3.33/VERSION0000664000175000001440000000000712626257402013067 0ustar timusers1.3.33 qrouter-1.3.33/console.tcl0000664000175000001440000000065712416240616014174 0ustar timusers# Tcl commands to run in the console before qrouter is initialized slave alias qrouter::consoledown wm withdraw . slave alias qrouter::consoleup wm deiconify . slave alias qrouter::consoleontop raise . # NOTE: This is not recommended for qrouter, where everything runs # off of the console. If the console is closed, then the program # should exit. # # wm protocol . WM_DELETE_WINDOW {tkcon slave slave qrouter::lowerconsole} qrouter-1.3.33/tclqrouter.c0000664000175000001440000016170112625161025014372 0ustar timusers/*--------------------------------------------------------------*/ /* tclqrouter.c: */ /* Tcl routines for qrouter command-line functions */ /* Copyright (c) 2013 Tim Edwards, Open Circuit Design, Inc. */ /*--------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include #include "qrouter.h" #include "maze.h" #include "qconfig.h" #include "lef.h" /* Global variables */ Tcl_HashTable QrouterTagTable; Tcl_Interp *qrouterinterp; Tcl_Interp *consoleinterp; int stepnet = -1; /* This hash table speeds up DEF file reading */ Tcl_HashTable InstanceTable; /* Command structure */ typedef struct { const char *cmdstr; void (*func)(); } cmdstruct; /* Forward declarations of commands */ extern int Tk_SimpleObjCmd(); extern int redraw(); extern int qrouter_map(); extern int qrouter_start(); extern int qrouter_stage1(); extern int qrouter_stage2(); extern int qrouter_writedef(); extern int qrouter_readdef(); extern int qrouter_readlef(); extern int qrouter_readconfig(); extern int qrouter_failing(); extern int qrouter_cost(); extern int qrouter_tag(); extern int qrouter_remove(); extern int qrouter_obs(); extern int qrouter_layerinfo(); extern int qrouter_priority(); extern int qrouter_ignore(); extern int qrouter_via(); extern int qrouter_resolution(); extern int qrouter_congested(); extern int qrouter_layers(); extern int qrouter_passes(); extern int qrouter_vdd(); extern int qrouter_gnd(); extern int qrouter_verbose(); extern int QuitCallback(); static cmdstruct qrouter_commands[] = { {"tag", (void *)qrouter_tag}, {"start", (void *)qrouter_start}, {"stage1", (void *)qrouter_stage1}, {"stage2", (void *)qrouter_stage2}, {"write_def", (void *)qrouter_writedef}, {"read_def", (void *)qrouter_readdef}, {"read_lef", (void *)qrouter_readlef}, {"read_config", (void *)qrouter_readconfig}, {"layer_info", (void *)qrouter_layerinfo}, {"obstruction", (void *)qrouter_obs}, {"ignore", (void *)qrouter_ignore}, {"priority", (void *)qrouter_priority}, {"via", (void *)qrouter_via}, {"resolution", (void *)qrouter_resolution}, {"congested", (void *)qrouter_congested}, {"layers", (void *)qrouter_layers}, {"passes", (void *)qrouter_passes}, {"vdd", (void *)qrouter_vdd}, {"gnd", (void *)qrouter_gnd}, {"failing", (void *)qrouter_failing}, {"remove", (void *)qrouter_remove}, {"cost", (void *)qrouter_cost}, {"map", (void *)qrouter_map}, {"verbose", (void *)qrouter_verbose}, {"redraw", (void *)redraw}, {"quit", (void *)QuitCallback}, {"", NULL} /* sentinel */ }; /*-----------------------*/ /* Tcl 8.4 compatibility */ /*-----------------------*/ #ifndef CONST84 #define CONST84 #endif /*----------------------------------------------------------------------*/ /* Deal with systems which don't define va_copy(). */ /*----------------------------------------------------------------------*/ #ifndef HAVE_VA_COPY #ifdef HAVE___VA_COPY #define va_copy(a, b) __va_copy(a, b) #else #define va_copy(a, b) a = b #endif #endif #ifdef ASG extern int SetDebugLevel(int *level); #endif /*----------------------------------------------------------------------*/ /* Reimplement strdup() to use Tcl_Alloc(). */ /*----------------------------------------------------------------------*/ char *Tcl_Strdup(const char *s) { char *snew; int slen; slen = 1 + strlen(s); snew = Tcl_Alloc(slen); if (snew != NULL) memcpy(snew, s, slen); return snew; } /*----------------------------------------------------------------------*/ /* Reimplement vfprintf() as a call to Tcl_Eval(). */ /* */ /* Since the string goes through the interpreter, we need to escape */ /* various characters like brackets, braces, dollar signs, etc., that */ /* will otherwise be modified by the interpreter. */ /*----------------------------------------------------------------------*/ void tcl_vprintf(FILE *f, const char *fmt, va_list args_in) { va_list args; static char outstr[128] = "puts -nonewline std"; char *outptr, *bigstr = NULL, *finalstr = NULL; int i, nchars, result, escapes = 0, limit; /* If we are printing an error message, we want to bring attention */ /* to it by mapping the console window and raising it, as necessary. */ /* I'd rather do this internally than by Tcl_Eval(), but I can't */ /* find the right window ID to map! */ if ((f == stderr) && (consoleinterp != qrouterinterp)) { Tk_Window tkwind; tkwind = Tk_MainWindow(consoleinterp); if ((tkwind != NULL) && (!Tk_IsMapped(tkwind))) result = Tcl_Eval(consoleinterp, "wm deiconify .\n"); result = Tcl_Eval(consoleinterp, "raise .\n"); } strcpy (outstr + 19, (f == stderr) ? "err \"" : "out \""); outptr = outstr; /* This mess circumvents problems with systems which do not have */ /* va_copy() defined. Some define __va_copy(); otherwise we must */ /* assume that args = args_in is valid. */ va_copy(args, args_in); nchars = vsnprintf(outptr + 24, 102, fmt, args); va_end(args); if (nchars >= 102) { va_copy(args, args_in); bigstr = Tcl_Alloc(nchars + 26); strncpy(bigstr, outptr, 24); outptr = bigstr; vsnprintf(outptr + 24, nchars + 2, fmt, args); va_end(args); } else if (nchars == -1) nchars = 126; for (i = 24; *(outptr + i) != '\0'; i++) { if (*(outptr + i) == '\"' || *(outptr + i) == '[' || *(outptr + i) == ']' || *(outptr + i) == '\\' || *(outptr + i) == '$') escapes++; } if (escapes > 0) { finalstr = Tcl_Alloc(nchars + escapes + 26); strncpy(finalstr, outptr, 24); escapes = 0; for (i = 24; *(outptr + i) != '\0'; i++) { if (*(outptr + i) == '\"' || *(outptr + i) == '[' || *(outptr + i) == ']' || *(outptr + i) == '\\' || *(outptr + i) == '$') { *(finalstr + i + escapes) = '\\'; escapes++; } *(finalstr + i + escapes) = *(outptr + i); } outptr = finalstr; } *(outptr + 24 + nchars + escapes) = '\"'; *(outptr + 25 + nchars + escapes) = '\0'; result = Tcl_Eval(consoleinterp, outptr); if (bigstr != NULL) Tcl_Free(bigstr); if (finalstr != NULL) Tcl_Free(finalstr); } /*------------------------------------------------------*/ /* Console output flushing which goes along with the */ /* routine tcl_vprintf() above. */ /*------------------------------------------------------*/ void tcl_stdflush(FILE *f) { Tcl_SavedResult state; static char stdstr[] = "::flush stdxxx"; char *stdptr = stdstr + 11; Tcl_SaveResult(qrouterinterp, &state); strcpy(stdptr, (f == stderr) ? "err" : "out"); Tcl_Eval(qrouterinterp, stdstr); Tcl_RestoreResult(qrouterinterp, &state); } /*----------------------------------------------------------------------*/ /* Reimplement fprintf() as a call to Tcl_Eval(). */ /*----------------------------------------------------------------------*/ void tcl_printf(FILE *f, const char *format, ...) { va_list ap; va_start(ap, format); tcl_vprintf(f, format, ap); va_end(ap); } /*----------------------------------------------------------------------*/ /* Implement tag callbacks on functions */ /* Find any tags associated with a command and execute them. */ /*----------------------------------------------------------------------*/ int QrouterTagCallback(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int objidx, result = TCL_OK; char *postcmd, *substcmd, *newcmd, *sptr, *sres; char *croot = Tcl_GetString(objv[0]); Tcl_HashEntry *entry; Tcl_SavedResult state; int reset = FALSE; int i, llen, cmdnum; entry = Tcl_FindHashEntry(&QrouterTagTable, croot); postcmd = (entry) ? (char *)Tcl_GetHashValue(entry) : NULL; if (postcmd) { substcmd = (char *)Tcl_Alloc(strlen(postcmd) + 1); strcpy(substcmd, postcmd); sptr = substcmd; /*--------------------------------------------------------------*/ /* Parse "postcmd" for Tk-substitution escapes */ /* Allowed escapes are: */ /* %W substitute the tk path of the calling window */ /* %r substitute the previous Tcl result string */ /* %R substitute the previous Tcl result string and */ /* reset the Tcl result. */ /* %[0-5] substitute the argument to the original command */ /* %N substitute all arguments as a list */ /* %% substitute a single percent character */ /* %* (all others) no action: print as-is. */ /*--------------------------------------------------------------*/ while ((sptr = strchr(sptr, '%')) != NULL) { switch (*(sptr + 1)) { case 'W': { char *tkpath = NULL; Tk_Window tkwind = Tk_MainWindow(interp); if (tkwind != NULL) tkpath = Tk_PathName(tkwind); if (tkpath == NULL) newcmd = (char *)Tcl_Alloc(strlen(substcmd)); else newcmd = (char *)Tcl_Alloc(strlen(substcmd) + strlen(tkpath)); strcpy(newcmd, substcmd); if (tkpath == NULL) strcpy(newcmd + (int)(sptr - substcmd), sptr + 2); else { strcpy(newcmd + (int)(sptr - substcmd), tkpath); strcat(newcmd, sptr + 2); } Tcl_Free(substcmd); substcmd = newcmd; sptr = substcmd; } break; case 'R': reset = TRUE; case 'r': sres = (char *)Tcl_GetStringResult(interp); newcmd = (char *)Tcl_Alloc(strlen(substcmd) + strlen(sres) + 1); strcpy(newcmd, substcmd); sprintf(newcmd + (int)(sptr - substcmd), "\"%s\"", sres); strcat(newcmd, sptr + 2); Tcl_Free(substcmd); substcmd = newcmd; sptr = substcmd; break; case '0': case '1': case '2': case '3': case '4': case '5': objidx = (int)(*(sptr + 1) - '0'); if ((objidx >= 0) && (objidx < objc)) { newcmd = (char *)Tcl_Alloc(strlen(substcmd) + strlen(Tcl_GetString(objv[objidx]))); strcpy(newcmd, substcmd); strcpy(newcmd + (int)(sptr - substcmd), Tcl_GetString(objv[objidx])); strcat(newcmd, sptr + 2); Tcl_Free(substcmd); substcmd = newcmd; sptr = substcmd; } else if (objidx >= objc) { newcmd = (char *)Tcl_Alloc(strlen(substcmd) + 1); strcpy(newcmd, substcmd); strcpy(newcmd + (int)(sptr - substcmd), sptr + 2); Tcl_Free(substcmd); substcmd = newcmd; sptr = substcmd; } else sptr++; break; case 'N': llen = 1; for (i = 1; i < objc; i++) llen += (1 + strlen(Tcl_GetString(objv[i]))); newcmd = (char *)Tcl_Alloc(strlen(substcmd) + llen); strcpy(newcmd, substcmd); strcpy(newcmd + (int)(sptr - substcmd), "{"); for (i = 1; i < objc; i++) { strcat(newcmd, Tcl_GetString(objv[i])); if (i < (objc - 1)) strcat(newcmd, " "); } strcat(newcmd, "}"); strcat(newcmd, sptr + 2); Tcl_Free(substcmd); substcmd = newcmd; sptr = substcmd; break; case '%': newcmd = (char *)Tcl_Alloc(strlen(substcmd) + 1); strcpy(newcmd, substcmd); strcpy(newcmd + (int)(sptr - substcmd), sptr + 1); Tcl_Free(substcmd); substcmd = newcmd; sptr = substcmd; break; default: break; } } /* Fprintf(stderr, "Substituted tag callback is \"%s\"\n", substcmd); */ /* Flush(stderr); */ Tcl_SaveResult(interp, &state); result = Tcl_Eval(interp, substcmd); if ((result == TCL_OK) && (reset == FALSE)) Tcl_RestoreResult(interp, &state); else Tcl_DiscardResult(&state); Tcl_Free(substcmd); } return result; } /*--------------------------------------------------------------*/ /* Add a command tag callback */ /*--------------------------------------------------------------*/ int qrouter_tag(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { Tcl_HashEntry *entry; char *hstring; int new; if (objc != 2 && objc != 3) return TCL_ERROR; entry = Tcl_CreateHashEntry(&QrouterTagTable, Tcl_GetString(objv[1]), &new); if (entry == NULL) return TCL_ERROR; hstring = (char *)Tcl_GetHashValue(entry); if (objc == 2) { Tcl_SetResult(interp, hstring, NULL); return TCL_OK; } if (strlen(Tcl_GetString(objv[2])) == 0) { Tcl_DeleteHashEntry(entry); } else { hstring = Tcl_Strdup(Tcl_GetString(objv[2])); Tcl_SetHashValue(entry, hstring); } return TCL_OK; } /*--------------------------------------------------------------*/ /* Cell macro lookup based on the hash table */ /*--------------------------------------------------------------*/ GATE DefFindInstance(char *name) { GATE ginst; Tcl_HashEntry *entry; entry = Tcl_FindHashEntry(&InstanceTable, name); ginst = (entry) ? (GATE)Tcl_GetHashValue(entry) : NULL; return ginst; } /*--------------------------------------------------------------*/ /* Cell macro hash table generation */ /* Given an instance record, create an entry in the hash table */ /* for the instance name, with the record entry pointing to the */ /* instance record. */ /*--------------------------------------------------------------*/ void DefHashInstance(GATE gateginfo) { int new; Tcl_HashEntry *entry; entry = Tcl_CreateHashEntry(&InstanceTable, gateginfo->gatename, &new); if (entry != NULL) Tcl_SetHashValue(entry, (ClientData)gateginfo); } /*--------------------------------------------------------------*/ /* Initialization procedure for Tcl/Tk */ /*--------------------------------------------------------------*/ int Qrouter_Init(Tcl_Interp *interp) { int cmdidx; Tk_Window tktop; char *tmp_s; char command[256]; char version_string[20]; /* Interpreter sanity checks */ if (interp == NULL) return TCL_ERROR; /* Remember the interpreter */ qrouterinterp = interp; if (Tcl_InitStubs(interp, "8.1", 0) == NULL) return TCL_ERROR; strcpy(command, "qrouter::"); /* Create the start command */ tktop = Tk_MainWindow(interp); /* Create all of the commands (except "simple") */ for (cmdidx = 0; qrouter_commands[cmdidx].func != NULL; cmdidx++) { sprintf(command + 9, "%s", qrouter_commands[cmdidx].cmdstr); Tcl_CreateObjCommand(interp, command, (Tcl_ObjCmdProc *)qrouter_commands[cmdidx].func, (ClientData)tktop, (Tcl_CmdDeleteProc *) NULL); } /* Command which creates a "simple" window. */ Tcl_CreateObjCommand(interp, "simple", (Tcl_ObjCmdProc *)Tk_SimpleObjCmd, (ClientData)tktop, (Tcl_CmdDeleteProc *) NULL); Tcl_Eval(interp, "lappend auto_path ."); sprintf(version_string, "%s", VERSION); Tcl_SetVar(interp, "QROUTER_VERSION", version_string, TCL_GLOBAL_ONLY); Tcl_Eval(interp, "namespace eval qrouter namespace export *"); Tcl_PkgProvide(interp, "Qrouter", version_string); /* Initialize the console interpreter, if there is one. */ if ((consoleinterp = Tcl_GetMaster(interp)) == NULL) consoleinterp = interp; /* Initialize the macro hash table */ Tcl_InitHashTable(&InstanceTable, TCL_STRING_KEYS); /* Initialize the command tag table */ Tcl_InitHashTable(&QrouterTagTable, TCL_STRING_KEYS); return TCL_OK; } /*------------------------------------------------------*/ /* Command "start" */ /*------------------------------------------------------*/ int qrouter_start(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int i, j, result, argc; char *scriptfile = NULL; char **argv; /* For compatibility with the original C code, convert Tcl */ /* object arguments to strings. Break out "-s ", */ /* which is not handled by runqrouter(), and source the */ /* script between runqrouter() and read_def(). */ argv = (char **)malloc(objc * sizeof(char *)); argc = 0; for (i = 0; i < objc; i++) { if (!strcmp(Tcl_GetString(objv[i]), "-s")) scriptfile = strdup(Tcl_GetString(objv[++i])); else argv[argc++] = strdup(Tcl_GetString(objv[i])); } result = runqrouter(argc, argv); if (result == 0) GUI_init(interp); for (i = 0; i < argc; i++) free(argv[i]); free(argv); if (scriptfile != NULL) { result = Tcl_EvalFile(interp, scriptfile); free(scriptfile); if (result != TCL_OK) return result; } if ((DEFfilename[0] != '\0') && (Nlgates == NULL)) { read_def(NULL); draw_layout(); } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "map" */ /* */ /* Specify what to draw in the graphics window */ /* */ /* map obstructions draw routes (normal) */ /* map congestion draw actual congestion */ /* map estimate draw estimated congestion */ /* map none route background is plain */ /* map routes draw routes over map */ /* map noroutes don't draw routes over map */ /*------------------------------------------------------*/ int qrouter_map(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int i, idx, result; static char *subCmds[] = { "obstructions", "congestion", "estimate", "none", "routes", "noroutes", NULL }; enum SubIdx { ObsIdx, CongIdx, EstIdx, NoneIdx, RouteIdx, NoRouteIdx }; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } else if ((result = Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)subCmds, "option", 0, &idx)) != TCL_OK) return result; switch (idx) { case ObsIdx: if ((mapType & MAP_MASK) != MAP_OBSTRUCT) { mapType &= ~MAP_MASK; mapType |= MAP_OBSTRUCT; draw_layout(); } break; case CongIdx: if ((mapType & MAP_MASK) != MAP_CONGEST) { mapType &= ~MAP_MASK; mapType |= MAP_CONGEST; draw_layout(); } break; case EstIdx: if ((mapType & MAP_MASK) != MAP_ESTIMATE) { mapType &= ~MAP_MASK; mapType |= MAP_ESTIMATE; draw_layout(); } break; case NoneIdx: if ((mapType & MAP_MASK) != MAP_NONE) { mapType &= ~MAP_MASK; mapType |= MAP_NONE; draw_layout(); } break; case RouteIdx: if ((mapType & DRAW_MASK) != DRAW_ROUTES) { mapType &= ~DRAW_MASK; mapType |= DRAW_ROUTES; draw_layout(); } break; case NoRouteIdx: if ((mapType & DRAW_MASK) != DRAW_NONE) { mapType &= ~DRAW_MASK; mapType |= DRAW_NONE; draw_layout(); } break; } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Find the net named "netname" in the list of nets */ /* and return a pointer to it. */ /* */ /* NOTE: Really need a hash table lookup here! */ /*------------------------------------------------------*/ NET LookupNet(char *netname) { NET net; int i; for (i = 0; i < Numnets; i++) { net = Nlnets[i]; if (!strcmp(net->netname, netname)) return net; } return NULL; } /*------------------------------------------------------*/ /* Command "stage1" */ /* */ /* Execute stage1 routing. This works through the */ /* entire netlist, routing as much as possible but not */ /* doing any rip-up and re-route. Nets that fail to */ /* route are put in the "FailedNets" list. */ /* */ /* The interpreter result is set to the number of */ /* failed routes at the end of the first stage. */ /* */ /* Options: */ /* */ /* stage1 debug Draw the area being searched in */ /* real-time. This slows down the */ /* algorithm and is intended only */ /* for diagnostic use. */ /* stage1 step Single-step stage one. */ /* stage1 mask none Don't limit the search area */ /* stage1 mask auto Select the mask automatically */ /* stage1 mask bbox Use the net bbox as a mask */ /* stage1 mask Set the mask size to , */ /* an integer typ. 0 and up. */ /* stage1 route Route net named only. */ /* */ /* stage1 force Force a terminal to be routable */ /*------------------------------------------------------*/ int qrouter_stage1(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { u_char dodebug; u_char dostep; int i, idx, idx2, val, result, failcount; NET net = NULL; static char *subCmds[] = { "debug", "mask", "route", "force", "step", NULL }; enum SubIdx { DebugIdx, MaskIdx, RouteIdx, ForceIdx, StepIdx }; static char *maskSubCmds[] = { "none", "auto", "bbox", NULL }; enum maskSubIdx { NoneIdx, AutoIdx, BboxIdx }; // Command defaults dodebug = FALSE; dostep = FALSE; maskMode = MASK_AUTO; // Mask mode is auto unless specified forceRoutable = FALSE; // Don't force unless specified if (objc >= 2) { for (i = 1; i < objc; i++) { if ((result = Tcl_GetIndexFromObj(interp, objv[i], (CONST84 char **)subCmds, "option", 0, &idx)) != TCL_OK) return result; switch (idx) { case DebugIdx: dodebug = TRUE; break; case StepIdx: dostep = TRUE; break; case ForceIdx: forceRoutable = TRUE; break; case RouteIdx: if (i >= objc - 1) { Tcl_WrongNumArgs(interp, 0, objv, "route ?net?"); return TCL_ERROR; } i++; net = LookupNet(Tcl_GetString(objv[i])); if (net == NULL) { Tcl_SetResult(interp, "No such net", NULL); return TCL_ERROR; } break; case MaskIdx: if (i >= objc - 1) { Tcl_WrongNumArgs(interp, 0, objv, "mask ?type?"); return TCL_ERROR; } i++; if ((result = Tcl_GetIndexFromObj(interp, objv[i], (CONST84 char **)maskSubCmds, "type", 0, &idx2)) != TCL_OK) { Tcl_ResetResult(interp); result = Tcl_GetIntFromObj(interp, objv[i], &val); if (result != TCL_OK) return result; else if (val < 0 || val > 200) { Tcl_SetResult(interp, "Bad mask value", NULL); return TCL_ERROR; } maskMode = (u_char)val; } else { switch(idx2) { case NoneIdx: maskMode = MASK_NONE; break; case AutoIdx: maskMode = MASK_AUTO; break; case BboxIdx: maskMode = MASK_BBOX; break; } } break; } } } if (dostep == FALSE) stepnet = -1; else stepnet++; if (net == NULL) failcount = dofirststage(dodebug, stepnet); else { if ((net != NULL) && (net->netnodes != NULL)) { result = doroute(net, (u_char)0, dodebug); failcount = (result == 0) ? 0 : 1; } } Tcl_SetObjResult(interp, Tcl_NewIntObj(failcount)); if (stepnet >= (Numnets - 1)) stepnet = -1; return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "stage2" */ /* */ /* Execute stage2 routing. This stage works through */ /* the "FailedNets" list, routing with collisions, and */ /* then ripping up the colliding nets and appending */ /* them to the "FailedNets" list. */ /* */ /* The interpreter result is set to the number of */ /* failed routes at the end of the second stage. */ /* */ /* Options: */ /* */ /* stage2 debug Draw the area being searched in */ /* real-time. This slows down the */ /* algorithm and is intended only */ /* for diagnostic use. */ /* stage2 step Single-step stage two */ /* stage2 mask none Don't limit the search area */ /* stage2 mask auto Select the mask automatically */ /* stage2 mask bbox Use the net bbox as a mask */ /* stage2 mask Set the mask size to , */ /* an integer typ. 0 and up. */ /* stage2 limit Fail route if solution collides */ /* with more than nets. */ /* stage2 route Route net named only. */ /* */ /* stage2 force Force a terminal to be routable */ /* stage2 tries Keep trying n additional times */ /*------------------------------------------------------*/ int qrouter_stage2(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { u_char dodebug; u_char dostep; int i, idx, idx2, val, result, failcount; NET net = NULL; static char *subCmds[] = { "debug", "mask", "limit", "route", "force", "tries", "step", NULL }; enum SubIdx { DebugIdx, MaskIdx, LimitIdx, RouteIdx, ForceIdx, TriesIdx, StepIdx }; static char *maskSubCmds[] = { "none", "auto", "bbox", NULL }; enum maskSubIdx { NoneIdx, AutoIdx, BboxIdx }; // Command defaults dodebug = FALSE; dostep = FALSE; maskMode = MASK_AUTO; // Mask mode is auto unless specified forceRoutable = FALSE; // Don't force unless specified ripLimit = 10; // Rip limit is 10 unless specified if (objc >= 2) { for (i = 1; i < objc; i++) { if ((result = Tcl_GetIndexFromObj(interp, objv[i], (CONST84 char **)subCmds, "option", 0, &idx)) != TCL_OK) return result; switch (idx) { case DebugIdx: dodebug = TRUE; break; case StepIdx: dostep = TRUE; break; case ForceIdx: forceRoutable = TRUE; break; case TriesIdx: if (i >= objc - 1) { Tcl_WrongNumArgs(interp, 0, objv, "tries ?num?"); return TCL_ERROR; } i++; result = Tcl_GetIntFromObj(interp, objv[i], &val); if (result != TCL_OK) return result; keepTrying = (u_char)val; break; case RouteIdx: if (i >= objc - 1) { Tcl_WrongNumArgs(interp, 0, objv, "route ?net?"); return TCL_ERROR; } i++; net = LookupNet(Tcl_GetString(objv[i])); if (net == NULL) { Tcl_SetResult(interp, "No such net", NULL); return TCL_ERROR; } break; case LimitIdx: if (i >= objc - 1) { Tcl_WrongNumArgs(interp, 0, objv, "limit ?num?"); return TCL_ERROR; } i++; result = Tcl_GetIntFromObj(interp, objv[i], &val); if (result != TCL_OK) return result; ripLimit = (u_char)val; break; case MaskIdx: if (i >= objc - 1) { Tcl_WrongNumArgs(interp, 0, objv, "mask ?type?"); return TCL_ERROR; } i++; if ((result = Tcl_GetIndexFromObj(interp, objv[i], (CONST84 char **)maskSubCmds, "type", 0, &idx2)) != TCL_OK) { Tcl_ResetResult(interp); result = Tcl_GetIntFromObj(interp, objv[i], &val); if (result != TCL_OK) return result; else if (val < 0 || val > 200) { Tcl_SetResult(interp, "Bad mask value", NULL); return TCL_ERROR; } maskMode = (u_char)val; } else { switch(idx2) { case NoneIdx: maskMode = MASK_NONE; break; case AutoIdx: maskMode = MASK_AUTO; break; case BboxIdx: maskMode = MASK_BBOX; break; } } break; } } } if (net == NULL) failcount = dosecondstage(dodebug, dostep); else failcount = route_net_ripup(net, dodebug); Tcl_SetObjResult(interp, Tcl_NewIntObj(failcount)); draw_layout(); return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "remove" */ /* */ /* Remove a net or nets, or all nets, from the */ /* design. */ /* */ /* Options: */ /* */ /* remove all Remove all nets from the design */ /* remove net [...] */ /* Remove the named net(s) from */ /* the design. */ /*------------------------------------------------------*/ int qrouter_remove(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int result, idx, i; NET net; static char *subCmds[] = { "all", "net", NULL }; enum SubIdx { AllIdx, NetIdx }; if (objc < 2) { Tcl_WrongNumArgs(interp, 0, objv, "?option?"); return TCL_ERROR; } else { if ((result = Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)subCmds, "option", 0, &idx)) != TCL_OK) return result; switch (idx) { case AllIdx: for (i = 0; i < Numnets; i++) { net = Nlnets[i]; ripup_net(net, (u_char)1); } draw_layout(); break; case NetIdx: for (i = 2; i < objc; i++) { net = LookupNet(Tcl_GetString(objv[i])); if (net != NULL) ripup_net(net, (u_char)1); } draw_layout(); break; } } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "failing" */ /* */ /* List the nets that have failed routing. */ /* */ /* Options: */ /* */ /* failing all Move all nets to FailedNets */ /* ordered by the standard metric */ /* failing unordered Move all nets to FailedNets, */ /* as originally ordered */ /*------------------------------------------------------*/ int qrouter_failing(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { Tcl_Obj *lobj; NETLIST nl, nlast; NET net; int i, failcount; if (objc == 2) { if (!strncmp(Tcl_GetString(objv[1]), "unorder", 7)) { // Free up FailedNets list and then move all // nets to FailedNets while (FailedNets != NULL) { nl = FailedNets->next; FailedNets = FailedNets->next; free(nl); } nlast = NULL; for (i = 0; i < Numnets; i++) { net = Nlnets[i]; nl = (NETLIST)malloc(sizeof(struct netlist_)); nl->net = net; nl->next = NULL; if (nlast == NULL) FailedNets = nl; else nlast->next = nl; nlast = nl; } } else if (!strncmp(Tcl_GetString(objv[1]), "all", 3)) { while (FailedNets != NULL) { nl = FailedNets->next; FailedNets = FailedNets->next; free(nl); } create_netorder(0); nlast = NULL; for (i = 0; i < Numnets; i++) { net = Nlnets[i]; nl = (NETLIST)malloc(sizeof(struct netlist_)); nl->net = net; nl->next = NULL; if (nlast == NULL) FailedNets = nl; else nlast->next = nl; nlast = nl; } } else if (!strncmp(Tcl_GetString(objv[1]), "summary", 7)) { failcount = countlist(FailedNets); lobj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, lobj, Tcl_NewIntObj(failcount)); Tcl_ListObjAppendElement(interp, lobj, Tcl_NewIntObj(Numnets)); Tcl_SetObjResult(interp, lobj); } else { Tcl_WrongNumArgs(interp, 0, objv, "all or unordered"); return TCL_ERROR; } } else { lobj = Tcl_NewListObj(0, NULL); for (nl = FailedNets; nl; nl = nl->next) { Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj(nl->net->netname, -1)); } Tcl_SetObjResult(interp, lobj); } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "read_lef" */ /*------------------------------------------------------*/ int qrouter_readlef(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { char *LEFfile; if (objc != 2) { Tcl_SetResult(interp, "No LEF filename specified!", NULL); return TCL_ERROR; } LEFfile = Tcl_GetString(objv[1]); LefRead(LEFfile); post_config(); return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "read_def" */ /*------------------------------------------------------*/ int qrouter_readdef(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { if ((DEFfilename[0] == '\0') && (objc != 2)) { Tcl_SetResult(interp, "No DEF filename specified!", NULL); return TCL_ERROR; } if (objc == 2) read_def(Tcl_GetString(objv[1])); else read_def(NULL); // Redisplay draw_layout(); return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "write_def" */ /*------------------------------------------------------*/ int qrouter_writedef(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { char *DEFoutfile = NULL; if (objc == 2) DEFoutfile = Tcl_GetString(objv[1]); else if (DEFfilename[0] == '\0') { Tcl_SetResult(interp, "No DEF filename specified!", NULL); return TCL_ERROR; } write_def(DEFoutfile); return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "read_config" */ /*------------------------------------------------------*/ int qrouter_readconfig(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { FILE *configFILE; char *configname = NULL; if (objc == 2) configname = Tcl_GetString(objv[1]); else { Tcl_SetResult(interp, "No configuration filename specified!", NULL); return TCL_ERROR; } configFILE = fopen(configname, "r"); if (configFILE == NULL) { Tcl_SetResult(interp, "Failed to open configuration file.", NULL); return TCL_ERROR; } read_config(configFILE, FALSE); return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "obstruction" */ /* */ /* Create an obstruction manually by specifying a */ /* rectangular bounding box and layer of the obstructed */ /* area. Without options, returns a list of the */ /* defined user obstruction areas. */ /* */ /* Options: */ /* */ /* obstruction */ /* obstruction */ /*------------------------------------------------------*/ int qrouter_obs(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { Tcl_Obj *lobj; Tcl_Obj *oobj; LefList lefl; char *layername; DSEG obs; int layer, result; double x1, x2, y1, y2; if (objc == 1) { lobj = Tcl_NewListObj(0, NULL); for (obs = UserObs; obs; obs = obs->next) { lefl = LefFindLayerByNum(obs->layer); if (lefl == NULL) continue; oobj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, oobj, Tcl_NewDoubleObj(obs->x1)); Tcl_ListObjAppendElement(interp, oobj, Tcl_NewDoubleObj(obs->x2)); Tcl_ListObjAppendElement(interp, oobj, Tcl_NewDoubleObj(obs->y1)); Tcl_ListObjAppendElement(interp, oobj, Tcl_NewDoubleObj(obs->y2)); Tcl_ListObjAppendElement(interp, oobj, Tcl_NewStringObj(lefl->lefName, -1)); Tcl_ListObjAppendElement(interp, lobj, oobj); } Tcl_SetObjResult(interp, lobj); } else if (objc != 6) { Tcl_WrongNumArgs(interp, 1, objv, "x1 x2 y1 y2 layer"); return TCL_ERROR; } else { layername = Tcl_GetString(objv[5]); layer = LefFindLayerNum(layername); if (layer < 0) { Tcl_SetResult(interp, "No such layer name", NULL); return TCL_ERROR; } else { result = Tcl_GetDoubleFromObj(interp, objv[1], &x1); if (result != TCL_OK) return result; result = Tcl_GetDoubleFromObj(interp, objv[2], &y1); if (result != TCL_OK) return result; result = Tcl_GetDoubleFromObj(interp, objv[3], &x2); if (result != TCL_OK) return result; result = Tcl_GetDoubleFromObj(interp, objv[4], &y2); if (result != TCL_OK) return result; obs = (DSEG)malloc(sizeof(struct dseg_)); obs->x1 = x1; obs->x2 = x2; obs->y1 = y1; obs->y2 = y2; obs->layer = layer; obs->next = UserObs; UserObs = obs; } } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "ignore" */ /* */ /* Specify one or more net names to be ignored by the */ /* router. With no options, returns a list of nets */ /* being ignored by the router. */ /* */ /* Options: */ /* */ /* ignore [ ...] */ /*------------------------------------------------------*/ int qrouter_ignore(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int i; NET net; Tcl_Obj *lobj; if (objc == 1) { lobj = Tcl_NewListObj(0, NULL); for (i = 0; i < Numnets; i++) { net = Nlnets[i]; if (net->flags & NET_IGNORED) { Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj(net->netname, -1)); } } Tcl_SetObjResult(interp, lobj); } else { for (i = 1; i < objc; i++) { net = LookupNet(Tcl_GetString(objv[i])); if (net == NULL) { Tcl_SetResult(interp, "No such net", NULL); return TCL_ERROR; } net->flags |= NET_IGNORED; } } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "priority" */ /* */ /* Specify one or more net names to be routed first by */ /* the router. With no options, returns a list of */ /* nets prioritized by the router. */ /* */ /* Options: */ /* */ /* priority [ ...] */ /*------------------------------------------------------*/ int qrouter_priority(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int i; char *netname; NET net; STRING cn, ctest; Tcl_Obj *lobj; if (objc == 1) { lobj = Tcl_NewListObj(0, NULL); for (i = 0; i < Numnets; i++) { net = Nlnets[i]; if (net->flags & NET_CRITICAL) { Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj(net->netname, -1)); } } Tcl_SetObjResult(interp, lobj); } else { for (i = objc - 1; i > 0; i--) { netname = Tcl_GetString(objv[i]); net = LookupNet(netname); if (net == NULL) { Tcl_SetResult(interp, "No such net", NULL); } else { net->flags |= NET_CRITICAL; for (cn = CriticalNet; cn && cn->next; cn = cn->next) { if (!cn->next) break; if (!strcmp(cn->next->name, netname)) { ctest = cn->next; cn->next = cn->next->next; ctest->next = CriticalNet; CriticalNet = ctest; } } } } create_netorder(0, NULL); } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "layer_info" */ /* */ /* Provide information gleaned from the LEF technology */ /* file or files */ /* */ /* Options: */ /* */ /* layer_info [all] */ /* layer_info | */ /* layer_info | width */ /* layer_info | pitch */ /* layer_info | orientation */ /* layer_info | offset */ /* layer_info | spacing */ /* layer_info maxlayer */ /* */ /* all: generate a list summary of route information */ /* in the format of the info file generated with */ /* the "-i" command-line switch. */ /* : generate a list summary of information for */ /* the specified route layer , format the */ /* same as for option "all". */ /* pitch: Return the layer pitch value. */ /* orientation: Return the layer orientation. */ /* offset: Return the layer offset value. */ /* spacing: Return the layer minimum spacing */ /* value. */ /* maxlayer: Return the maximum number of route layers */ /* defined by the technology. */ /* */ /* No option is the same as option "layer_info all" */ /*------------------------------------------------------*/ int qrouter_layerinfo(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { Tcl_Obj *lobj, *oobj; int i, idx, idx2, val, result, layer; char *layername; static char *subCmds[] = { "all", "maxlayer", NULL }; enum SubIdx { AllIdx, MaxLayerIdx }; static char *layerSubCmds[] = { "width", "pitch", "orientation", "offset", "spacing", NULL }; enum layerSubIdx { WidthIdx, PitchIdx, OrientIdx, OffsetIdx, SpacingIdx }; idx = idx2 = -1; if (objc < 2) { idx = AllIdx; } else { layername = Tcl_GetString(objv[1]); layer = LefFindLayerNum(layername); if (layer == -1) { if ((result = Tcl_GetIntFromObj(interp, objv[1], &val)) == TCL_OK) { layer = val; } else { Tcl_ResetResult(interp); if ((result = Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)subCmds, "option", 0, &idx)) != TCL_OK) { return result; } } } else if (objc >= 3) { if ((result = Tcl_GetIndexFromObj(interp, objv[2], (CONST84 char **)layerSubCmds, "option", 0, &idx2)) != TCL_OK) { return result; } layer = LefFindLayerNum(layername); } else { layer = LefFindLayerNum(layername); } } if (idx == -1 && layer == -1) { Tcl_SetResult(interp, "Bad layer", NULL); return TCL_ERROR; } if (layer < 0 || layer >= Num_layers) { Tcl_SetResult(interp, "Bad layer", NULL); return TCL_ERROR; } switch (idx) { case AllIdx: oobj = Tcl_NewListObj(0, NULL); for (i = 0; i < Num_layers; i++) { lobj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj(LefGetRouteName(i), -1)); Tcl_ListObjAppendElement(interp, lobj, Tcl_NewDoubleObj(LefGetRoutePitch(i))); Tcl_ListObjAppendElement(interp, lobj, Tcl_NewDoubleObj(LefGetRouteWidth(i))); if (LefGetRouteOrientation(i) == 1) Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj("horizontal", -1)); else Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj("vertical", -1)); Tcl_ListObjAppendElement(interp, oobj, lobj); } Tcl_SetObjResult(interp, oobj); break; case MaxLayerIdx: Tcl_SetObjResult(interp, Tcl_NewIntObj(Num_layers)); break; } switch (idx2) { case WidthIdx: Tcl_SetObjResult(interp, Tcl_NewDoubleObj(LefGetRouteWidth(layer))); break; case PitchIdx: Tcl_SetObjResult(interp, Tcl_NewDoubleObj(LefGetRoutePitch(layer))); break; case OrientIdx: if (LefGetRouteOrientation(layer) == (u_char)0) Tcl_SetObjResult(interp, Tcl_NewStringObj("vertical", -1)); else Tcl_SetObjResult(interp, Tcl_NewStringObj("horizontal", -1)); break; case OffsetIdx: Tcl_SetObjResult(interp, Tcl_NewDoubleObj(LefGetRouteOffset(layer))); break; case SpacingIdx: Tcl_SetObjResult(interp, Tcl_NewDoubleObj(LefGetRouteSpacing(layer))); break; default: if (idx != -1) break; lobj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj(LefGetRouteName(layer), -1)); Tcl_ListObjAppendElement(interp, lobj, Tcl_NewDoubleObj(LefGetRoutePitch(layer))); Tcl_ListObjAppendElement(interp, lobj, Tcl_NewDoubleObj(LefGetRouteWidth(layer))); if (LefGetRouteOrientation(layer) == 1) Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj("horizontal", -1)); else Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj("vertical", -1)); Tcl_SetObjResult(interp, lobj); break; } } /*------------------------------------------------------*/ /* Command "via" */ /* */ /* Various via configuration options for qrouter. */ /* */ /* stack: Value is the maximum number of vias that may */ /* be stacked directly on top of each other at */ /* a single point. Value "none", "0", and "1" */ /* all mean the same thing. */ /* */ /* via_pattern: If vias are non-square, then they are */ /* placed in a checkerboard pattern, with every */ /* other via rotated 90 degrees. If inverted, */ /* the rotation is swapped relative to the grid */ /* positions used in the non-inverted case. */ /* */ /* Options: */ /* */ /* via stack [none|all|] */ /* via pattern [normal|inverted] */ /*------------------------------------------------------*/ int qrouter_via(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int idx, idx2, result, value; static char *subCmds[] = { "stack", "pattern", NULL }; enum SubIdx { StackIdx, PatternIdx }; static char *stackSubCmds[] = { "none", "all", NULL }; enum stackSubIdx { NoneIdx, AllIdx }; static char *patternSubCmds[] = { "none", "normal", "invert", NULL }; enum patternSubIdx { PatNoneIdx, PatNormalIdx, PatInvertIdx }; if (objc >= 2) { if ((result = Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)subCmds, "option", 0, &idx)) != TCL_OK) return result; if (objc == 2) { switch (idx) { case StackIdx: Tcl_SetObjResult(interp, Tcl_NewIntObj(StackedContacts)); break; case PatternIdx: Tcl_SetObjResult(interp, Tcl_NewStringObj( patternSubCmds[ViaPattern + 1], -1)); break; } } else { switch (idx) { case StackIdx: result = Tcl_GetIntFromObj(interp, objv[2], &value); if (result == TCL_OK) { if (value <= 0) value = 1; else if (value >= Num_layers) value = Num_layers - 1; StackedContacts = value; break; } Tcl_ResetResult(interp); if ((result = Tcl_GetIndexFromObj(interp, objv[2], (CONST84 char **)stackSubCmds, "option", 0, &idx2)) != TCL_OK) return result; switch (idx2) { case NoneIdx: StackedContacts = 1; break; case AllIdx: StackedContacts = Num_layers - 1; break; } break; case PatternIdx: if ((result = Tcl_GetIndexFromObj(interp, objv[2], (CONST84 char **)patternSubCmds, "option", 0, &idx2)) != TCL_OK) return result; ViaPattern = idx2 - 1; break; } } } else { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "verbose" */ /* */ /* Set the level of how much output to print to the */ /* console. 0 is minimal output, 4 is maximum output */ /* With no argument, return the level of verbose. */ /* */ /* Options: */ /* */ /* resolution [] */ /*------------------------------------------------------*/ int qrouter_verbose(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int result, value; if (objc == 1) { Tcl_SetObjResult(interp, Tcl_NewIntObj(Verbose)); } else if (objc == 2) { result = Tcl_GetIntFromObj(interp, objv[1], &value); if (result != TCL_OK) return result; if (value < 0 || value > 255) { Tcl_SetResult(interp, "Verbose level out of range", NULL); return TCL_ERROR; } Verbose = (u_char)value; } else { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "resolution" */ /* */ /* Set the level of resolution of the output relative */ /* to the base units of centimicrons. The default */ /* value of 1 rounds all output values to the nearest */ /* centimicron; value 10 is to the nearest nanometer, */ /* and so forth. */ /* With no argument, return the value of the output */ /* resolution. */ /* */ /* Options: */ /* */ /* resolution [] */ /*------------------------------------------------------*/ int qrouter_resolution(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int result, value; if (objc == 1) { Tcl_SetObjResult(interp, Tcl_NewIntObj(Scales.iscale)); } else if (objc == 2) { result = Tcl_GetIntFromObj(interp, objv[1], &value); if (result != TCL_OK) return result; if (value < 1) { Tcl_SetResult(interp, "Resolution out of range", NULL); return TCL_ERROR; } Scales.iscale = value; } else { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "layers" */ /* */ /* Set the number of layers used for routing */ /* independently of the number defined in the */ /* technology LEF file. Without an argument, return */ /* the number of layers being used (this is not the */ /* same as "layer_info maxlayer") */ /* */ /* Options: */ /* */ /* layers [] */ /*------------------------------------------------------*/ int qrouter_layers(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int result, value; if (objc == 1) { Tcl_SetObjResult(interp, Tcl_NewIntObj(Num_layers)); } else if (objc == 2) { result = Tcl_GetIntFromObj(interp, objv[1], &value); if (result != TCL_OK) return result; if (value <= 0 || value > LefGetMaxLayer()) { Tcl_SetResult(interp, "Number of layers out of range", NULL); return TCL_ERROR; } Num_layers = value; } else { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "passes" */ /* */ /* Set the maximum number of attempted passes of the */ /* route search algorithm, where the routing */ /* constraints (maximum cost and route area mask) are */ /* relaxed on each pass. */ /* With no argument, return the value for the maximum */ /* number of passes. */ /* The default number of passes is 10 and normally */ /* there is no reason for the user to change it. */ /* */ /* Options: */ /* */ /* passes [] */ /*------------------------------------------------------*/ int qrouter_passes(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int result, value; if (objc == 1) { Tcl_SetObjResult(interp, Tcl_NewIntObj(Numpasses)); } else if (objc == 2) { result = Tcl_GetIntFromObj(interp, objv[1], &value); if (result != TCL_OK) return result; if (value <= 0) { Tcl_SetResult(interp, "Number of passes out of range", NULL); return TCL_ERROR; } Numpasses = value; } else { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "vdd" */ /* */ /* Set the name of the net used for VDD power routing */ /* With no argument, return the name of the power */ /* net. */ /* */ /* Options: */ /* */ /* vdd [] */ /*------------------------------------------------------*/ int qrouter_vdd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { if (objc == 1) { if (vddnet == NULL) Tcl_SetObjResult(interp, Tcl_NewStringObj("(none)", -1)); else Tcl_SetObjResult(interp, Tcl_NewStringObj(vddnet, -1)); } else if (objc == 2) { if (vddnet != NULL) free(vddnet); vddnet = strdup(Tcl_GetString(objv[1])); } else { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "gnd" */ /* */ /* Set the name of the net used for ground routing. */ /* With no argument, return the name of the ground */ /* net. */ /* */ /* Options: */ /* */ /* gnd [] */ /*------------------------------------------------------*/ int qrouter_gnd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { if (objc == 1) { if (gndnet == NULL) Tcl_SetObjResult(interp, Tcl_NewStringObj("(none)", -1)); else Tcl_SetObjResult(interp, Tcl_NewStringObj(gndnet, -1)); } else if (objc == 2) { if (gndnet != NULL) free(gndnet); gndnet = strdup(Tcl_GetString(objv[1])); } else { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ /* Command "cost" */ /* */ /* Query or set the value of a cost function */ /* */ /* Options: */ /* */ /* cost segment */ /* cost via */ /* cost jog */ /* cost crossover */ /* cost block */ /* cost conflict */ /*------------------------------------------------------*/ int qrouter_cost(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int idx, result, value; static char *subCmds[] = { "segment", "via", "jog", "crossover", "block", "conflict", NULL }; enum SubIdx { SegIdx, ViaIdx, JogIdx, XOverIdx, BlockIdx, ConflictIdx }; value = 0; if (objc == 3) { result = Tcl_GetIntFromObj(interp, objv[2], &value); if (result != TCL_OK) return result; if (value <= 0) { Tcl_SetResult(interp, "Bad cost value", NULL); return TCL_ERROR; } } else if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); return TCL_ERROR; } if ((result = Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)subCmds, "option", 0, &idx)) != TCL_OK) return result; switch (idx) { case SegIdx: if (objc == 2) Tcl_SetObjResult(interp, Tcl_NewIntObj(SegCost)); else SegCost = value; break; case ViaIdx: if (objc == 2) Tcl_SetObjResult(interp, Tcl_NewIntObj(ViaCost)); else ViaCost = value; break; case JogIdx: if (objc == 2) Tcl_SetObjResult(interp, Tcl_NewIntObj(JogCost)); else JogCost = value; break; case XOverIdx: if (objc == 2) Tcl_SetObjResult(interp, Tcl_NewIntObj(XverCost)); else XverCost = value; break; case BlockIdx: if (objc == 2) Tcl_SetObjResult(interp, Tcl_NewIntObj(BlockCost)); else BlockCost = value; break; case ConflictIdx: if (objc == 2) Tcl_SetObjResult(interp, Tcl_NewIntObj(ConflictCost)); else ConflictCost = value; break; } return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ typedef struct clist_ *CLIST; typedef struct clist_ { GATE gate; double congestion; } Clist; /*------------------------------------------------------*/ /* Compare function for qsort() */ /*------------------------------------------------------*/ int compcong(CLIST *a, CLIST *b) { CLIST p = *a; CLIST q = *b; if (p->congestion < q->congestion) return (1); else if (p->congestion > q->congestion) return (-1); else return (0); } /*------------------------------------------------------*/ /* Command "congested" */ /* */ /* Return a list of instances, ranked by congestion. */ /* This list can be passed back to a placement tool to */ /* direct it to add padding around these cells to ease */ /* congestion and make the layout more routable. */ /* */ /* Options: */ /* */ /* congested List the top congested */ /* gates in the design. */ /*------------------------------------------------------*/ int qrouter_congested(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { NET net; int i, x, y, nwidth, nheight, area, length; int value, entries, numgates, result; float density, *Congestion; CLIST *cgates, csrch; GATE gsrch; struct seg_ bbox; double dx, dy, cavg; Tcl_Obj *lobj, *dobj; if (objc == 2) { result = Tcl_GetIntFromObj(interp, objv[1], &entries); if (result != TCL_OK) return result; if (value <= 0) { Tcl_SetResult(interp, "List size must be > 0", NULL); return TCL_ERROR; } } else entries = 0; Congestion = (float *)calloc(NumChannelsX[0] * NumChannelsY[0], sizeof(float)); // Use net bounding boxes to estimate congestion for (i = 0; i < Numnets; i++) { net = Nlnets[i]; nwidth = (net->xmax - net->xmin + 1); nheight = (net->ymax - net->ymin + 1); area = nwidth * nheight; if (nwidth > nheight) { length = nwidth + (nheight >> 1) * net->numnodes; } else { length = nheight + (nwidth >> 1) * net->numnodes; } density = (float)length / (float)area; for (x = net->xmin; x < net->xmax; x++) for (y = net->ymin; y < net->ymax; y++) Congestion[OGRID(x, y, 0)] += density; } // Use instance bounding boxes to estimate average congestion // in the area of an instance. numgates = 0; for (gsrch = Nlgates; gsrch; gsrch = gsrch->next) numgates++; cgates = (CLIST *)malloc(numgates * sizeof(CLIST)); i = 0; for (gsrch = Nlgates; gsrch; gsrch = gsrch->next) { // Ignore pins, as the point of congestion planning // is to add padding to the core instances; including // pins just makes it harder for the placement script // to process the information. if (gsrch->gatetype == PinMacro) continue; cgates[i] = (CLIST)malloc(sizeof(Clist)); dx = gsrch->placedX; dy = gsrch->placedY; bbox.x1 = (int)((dx - Xlowerbound) / PitchX[0]) - 1; bbox.y1 = (int)((dy - Ylowerbound) / PitchY[0]) - 1; dx = gsrch->placedX + gsrch->width; dy = gsrch->placedY + gsrch->height; bbox.x2 = (int)((dx - Xlowerbound) / PitchX[0]) - 1; bbox.y2 = (int)((dy - Ylowerbound) / PitchY[0]) - 1; cavg = 0.0; for (x = bbox.x1; x <= bbox.x2; x++) { for (y = bbox.y1; y <= bbox.y2; y++) { cavg += Congestion[OGRID(x, y, 0)]; } } cavg /= (bbox.x2 - bbox.x1 + 1); cavg /= (bbox.y2 - bbox.y1 + 1); cgates[i]->gate = gsrch; cgates[i++]->congestion = cavg / Num_layers; } // Re-set "numgates", because we have rejected pins from the // original count. numgates = i; // Order Clist and copy contents back to the interpreter as a list qsort((char *)cgates, numgates, (int)sizeof(CLIST), (__compar_fn_t)compcong); lobj = Tcl_NewListObj(0, NULL); if (entries == 0) entries = numgates; else if (entries > numgates) entries = numgates; for (i = 0; i < entries; i++) { csrch = cgates[i]; gsrch = csrch->gate; dobj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, dobj, Tcl_NewStringObj(gsrch->gatename, -1)); Tcl_ListObjAppendElement(interp, dobj, Tcl_NewDoubleObj(csrch->congestion)); Tcl_ListObjAppendElement(interp, lobj, dobj); } Tcl_SetObjResult(interp, lobj); // Cleanup free(Congestion); for (i = 0; i < numgates; i++) free(cgates[i]); free(cgates); return QrouterTagCallback(interp, objc, objv); } /*------------------------------------------------------*/ qrouter-1.3.33/README0000664000175000001440000002100612625141662012700 0ustar timusers------------------------------------------------- Qrouter version 1.3 Detail netlist router for ASICs (c) 2014 by Tim Edwards Released under Gnu Public License ---------------------------------------------- ---------------------------------------------- Release notes: ---------------------------------------------- Version 1.3 ------------ Branch created September 16, 2014 mainly for the purpose of making the existing version 1.2 the stable branch, particularly as version 1.2 is required for qflow. Version 1.2 ------------ Branch of 1.1 that puts qrouter in a Tcl/Tk environment and includes routines to generate and draw into a graphics window. Code reorganized into three main sections that are called from the Tcl command line as "stage1", "stage2", and "write_def". The front-end process of reading in the LEF and DEF files and configuring the routing environment will be added to the command set, eventually. Based on analysis from the visualization of the router, the code has been rewritten to speed up the routing during multi-tap (more than 2 connections) nets, so that previous search results remain in place after each route, avoiding redundant searching. This speeds up qrouter by a factor of about 2x. A masking function that limits routes to a specific defined portion of the layout speeds up qrouter by a factor of about 30x. Version 1.1 ------------ Second major release. Revised the "proute" structure so that its position information refers to the position of the structure itself and not of the predecessor. This requires setting up proute structures for every point on the source net, but makes it possible to specify one or more alternate predecessors for each potential route position. Added handling of routes with larger size and pitch on the higher layers. Added handling of technologies that do not allow contacts to be stacked arbitrarily. Some preliminary work in search optimization. Finding a viable route (any viable route) quickly is the key to setting a bound on cost early and prevent multiple passes over many points. Added code for detailed analysis of port geometry and taking steps necessary to avoid generating DRC errors. Redesigned internal structures so that nodes are not in an independent list, but only listed under their assigned net. Routes are assigned to nets, not to nodes. Added the ability to read in existing route geometry and add it to the database. Version 1.0 ------------ First release. This is work in progess on a professional-grade multi-layer maze router. First release implements the standard Lee algorithm. However, a modified Lee algorithm is used that presents all nodes of the network (other than the source node) as targets. As each target node is reached, in order of lowest cost, the target node and its route to the source are added to the source node, and the process repeated until there are no more target nodes. The implementation is geometry-aware, to the extent that all node and obstruction geometry is present in the LEF file used to define the standard cell macros. The implementation uses the open standard LEF and DEF formats. Standard cell definitions and routing layer definitions are read in from the LEF file, and cell placement information and an unrouted network are read from the DEF file. Output is a copy of the original input DEF file, annotated with the physical routes. ---------------------------------------------- Compilation & installation: ---------------------------------------------- The system runs under autoconf, and so has the standard compile and install sequence: ./configure make make install Options to configure: --with-prefix= overrides the standard install location of /usr/local --with-libdir= overrides the standard search location for configuration files, /usr/local/share/qrouter --with-tcl= path to tclConfig.sh file. --with-tk= path to tkConfig.sh file. ---------------------------------------------- Usage: ---------------------------------------------- qrouter [-noc] [-s ] This is the normal invocation, where a Tcl-script specified by contains all of the configuration information, specifies where to read LEF and DEF files, how to perform the routing, and where to write the output DEF file. All commands in the script can alternatively be entered on the Tcl command line after starting qrouter. The "-noc" option does not invoke the Tk console on startup, which is best for batch operation, as text output to the console can slow down the routing process. qrouter [-c ] [options] where is without an extension. File .def is assumed to exist and to define cell placement and netlist information. File is assumed to exist and contains basic routing parameters, or points to a LEF file containing detailed routing parameters. If this option is not specified, then the default configuration file name of "route.cfg" is used. ---------------------------------------------- Completed development tasks: ---------------------------------------------- 1. New algorithm for routing nodes of a network, in which route_segs calculates costs out from source to any node in the network, settling on the minimum, and this continues until there are no nodes left to route. 2. Need to compute obstruction areas around nodes and mark them (e.g., with a flag) so that they can interpreted as obstructions when routing a different net, and available space when routing the node's net. 3. Rework the crossover cost method. Currently it does not account for the vertical layer, and so gives a high crossover cost to layers that are more than one route level above a node and would not block it. 4. Stub routing to nodes from unobstructed positions smaller than the route pitch but outside of the tap geometry. 5. Crossover costing removed for all terminals on completed routes. 6. Replace linked list code with simpler linked lists, no dependency on non-open-source linked-list code. 7. Added the ability to specify additional obstruction areas in the route.cfg file. 8. Increased the route width to the width of a via where the distance between a via and a terminal is less than the route metal's spacing rule. This cannot be done with normal routes in a DEF file, so it is added on as a "specialnets" section. 9. Collect all unroutable nets and route them with other nets marked as high-cost instead of obstructions. Analyze all the resultant collisions between nets, and proceed with an iterative rip-up and reroute algorithm. 10. When a net is ripped up to remove it from the path of a net being routed in the 2nd stage, the ripped-up net is added to a list in the routed net so that it will not be ripped up to make way for that net again. This prevents infinite looping in the 2nd stage. 11. Clean up the DEF file reader with a proper parser ported from magic, like the LEF file reader was. 12. Add a Tcl/Tk command-line interface for interactive routing and display. 13. Recast the config file as a set of Tcl command-line commands to execute. All original setup options have corresponding commands in the Tcl interpreter. The config file and its parsing is retained for backwards compatibility. 14. Vias can be larger than metal routes. Need to identify positions as obstructions to vias only. 15. Make Euclidean geometry checks instead of Manhattan geometry checks. ---------------------------------------------- Development to do: ---------------------------------------------- 1. Handle nets in the input DEF file that are already routed by adding them as obstructions to the route grid. 2. Final stage should rip up and reroute each network in turn, with all crossover costing removed, so that each route will be cleaner (to be done by Tcl commands acting on individual routes. Can be run as a simple Tcl script). 3. Need to normalize the segment and jog costs to the track pitch, so that costs do not give preference to the route layers with the widest track pitch. 4. Need a command-line switch (and/or Tcl command) to disable the specialnets section. 5. Sort trunk lines so no trunk lines overlap prior to routing. 6. Apply costing to terminals, giving higher cost to terminals with offsets and the lowest cost to simple on-grid contacts. ------------------------------------------------- qrouter-1.3.33/qrouter.tcl.in0000664000175000001440000001221412607327770014641 0ustar timusers#------------------------------------------------------ # Tcl startup script for qrouter #------------------------------------------------------ namespace path {::tcl::mathop ::tcl::mathfunc} set tcllibdir [array get env "QROUTER_LIB_DIR"] if {$tcllibdir == {}} { set QROUTER_LIB_DIR LIBDIR } else { set QROUTER_LIB_DIR [lindex $tcllibdir 1] } unset tcllibdir if {[string compare $tcl_platform(platform) "windows"] == 0} { set libext .dll } else { set libext .so } load ${QROUTER_LIB_DIR}/qrouter$libext package require Qrouter proc pushnamespace { name } { set y [namespace eval ${name} info commands ::${name}::*] set z [info commands] foreach v $y { regsub -all {\*} $v {\\*} i set x [namespace tail $i] if {[lsearch $z $x] < 0} { namespace import $i } else { puts "Warning: ${name} command '$x' use fully-qualified name '$v'" } } } proc popnamespace { name } { set z [info commands] set l [expr [string length ${name}] + 5] while {[set v [lsearch $z ${name}_tcl_*]] >= 0} { set y [lindex $z $v] set w [string range $y $l end] interp alias {} ::$w {} rename ::$y ::$w puts "Info: replacing ::$w with ::$y" } namespace forget ::${name}::* } set auto_noexec 1 ;# don't EVER call UNIX commands w/o "shell" in front #--------------------------------------------------------- # Internally-defined procedures (equivalent to commands) #--------------------------------------------------------- #--------------------------------------------------------- # Write the result of the "congested" command out to a # file, with " " per # line of output, one for each instance, ordered. #--------------------------------------------------------- proc qrouter::write_congested {filename} { puts stdout "Writing congestion information into $filename" if {![catch {open $filename w} fcon]} { puts $fcon "Qrouter congestion summary" puts $fcon "--------------------------" set flist [failing summary] set failures [lindex $flist 0] set numnets [lindex $flist 1] puts $fcon "Failures: $failures $numnets" puts $fcon "--------------------------" set clist [congested] foreach cpair $clist { set inst [lindex $cpair 0] set value [lindex $cpair 1] puts $fcon "$inst $value" } close $fcon } else { puts stderr "Error: can't open file $filename for output" } } #--------------------------------------------------------- # Standard sequence of events (subject to change): # Upon first success, write the DEF file output and quit. # If "stage2 mask none" leaves failing routes, then write # the routes done so far to the DEF file output and remain # in the interpreter. If "stage2 mask none" leaves fewer # than five routes (a very ad hoc number), give it a # second try. #--------------------------------------------------------- proc qrouter::standard_route {} { if {![stage1]} {write_def; quit} if {![stage2]} {write_def; quit} set result [stage2 mask none] if {$result < 5} {set result [stage2 mask none]} write_def if {$result == 0} {quit} } #------------------------------------------------------ # First alternative routing script. Do the quickest # (default) stage1 and stage2 routes. If stage2 # leaves route failures, then write out the list of # instances with congestion information, so that this # information can be fed back to the placement tool # in hopes of producing a routable layout on the next # iteration. Rather than returning to the interpreter # on route failure, it always quits. #------------------------------------------------------ proc qrouter::congestion_route {filename} { if {![stage1]} {write_def; quit} set result [stage2 mask none] if {$result < 5} {set result [stage2 mask none]} if {$result != 0} { qrouter::write_congested $filename } write_def quit } #------------------------------------------------------ pushnamespace qrouter #------------------------------------------------------ # GUI setup #------------------------------------------------------ set appname .qrouter set appframe ${appname}.dframe set drawwindow ${appframe}.drawing if {![catch {toplevel ${appname}}]} { frame ${appframe} pack ${appframe} -side left -expand true -fill both simple ${drawwindow} -width 1000 -height 800 pack ${drawwindow} -expand true -fill both bind ${appframe} redraw bind ${appframe} redraw bind ${appframe} redraw wm withdraw . } proc qrouter::lowerconsole {} { consoledown } puts stdout "Qrouter detail maze router version VERSION.REVISION" set autoquit 0 set autoroute 0 set argafter {start} for {set i 0} {$i < $argc} {incr i 1} { set x [lindex $argv $i] switch $x { "-i" - "-h" {set autoquit 1} "-c" {set autoroute 1} } lappend argafter $x } eval $argafter # NOTE: Having a file "route.cfg" in the current directory is # equivalent to specifying "-c ", so autoroute should be set if {$autoroute == 0} { if [file exists route.cfg] { set autoroute 1 } } if {$autoquit} quit if {$autoroute} { qrouter::standard_route } qrouter-1.3.33/node.c0000664000175000001440000026737712624703226013137 0ustar timusers/*--------------------------------------------------------------*/ /* node.c -- Generation of detailed network and obstruction */ /* information on the routing grid based on the geometry of the */ /* layout of the standard cell macros. */ /* */ /*--------------------------------------------------------------*/ /* Written by Tim Edwards, June, 2011, based on work by Steve */ /* Beccue. */ /*--------------------------------------------------------------*/ #include #include #include #include #include "qrouter.h" #include "node.h" #include "qconfig.h" #include "lef.h" /*--------------------------------------------------------------*/ /* Comparison routine used for qsort. Sort nets by number of */ /* nodes. */ /*--------------------------------------------------------------*/ int compNets(NET *a, NET *b) { NET p = *a; NET q = *b; // NULL nets get shoved up front if (p == NULL) return ((q == NULL) ? 0 : -1); if (q == NULL) return 1; // Sort critical nets at the front by assigned order if (p->flags & NET_CRITICAL) { if (q->flags & NET_CRITICAL) { return (p->netorder < q->netorder) ? -1 : 1; } else return -1; } // Otherwise sort by number of nodes if (p->numnodes < q->numnodes) return 1; if (p->numnodes > q->numnodes) return -1; return 0; } /*--------------------------------------------------------------*/ /* Alternative net comparison used for qsort. Sort nets by */ /* minimum dimension of the bounding box, and if equal, by the */ /* number of nodes in the net. Bounding box dimensions are */ /* ordered smallest to largest, and number of nodes are ordered */ /* largest to smallest. */ /*--------------------------------------------------------------*/ int altCompNets(NET *a, NET *b) { NET p = *a; NET q = *b; int pwidth, qwidth, pheight, qheight, pdim, qdim; // Any NULL nets get shoved up front if (p == NULL) return ((q == NULL) ? 0 : -1); if (q == NULL) return 1; // Sort critical nets at the front by assigned order if (p->flags & NET_CRITICAL) { if (q->flags & NET_CRITICAL) { return (p->netorder < q->netorder) ? -1 : 1; } else return -1; } // Otherwise sort as described above. pwidth = p->xmax - p->xmin; pheight = p->ymax - p->ymin; pdim = (pwidth > pheight) ? pheight : pwidth; qwidth = q->xmax - q->xmin; qheight = q->ymax - q->ymin; qdim = (qwidth > qheight) ? qheight : qwidth; if (pdim < qdim) return (-1); else if (pdim > qdim) return (1); else { if (p->numnodes < q->numnodes) return (1); if (p->numnodes > q->numnodes) return (-1); return (0); } } /*--------------------------------------------------------------*/ /* create_netorder --- assign indexes to net->netorder */ /* Re-sort Nlnets according to net order. Since Nlnets is a */ /* global variable, nothing is returned from this routine. */ /* */ /* method = 0 */ /* Nets are ordered simply from those with the most nodes */ /* to those with the fewest. However, any nets marked */ /* critical in the configuration or critical net files */ /* will be given precedence. */ /* */ /* method = 1 */ /* Nets are ordered by minimum bounding box dimension. */ /* This is based on the principle that small or narrow */ /* nets have little room to be moved around without */ /* greatly increasing the net length. If these are put */ /* down first, then remaining nets can route around them. */ /*--------------------------------------------------------------*/ void create_netorder(u_char method) { int i, j, max; NET net; STRING cn; i = 1; for (cn = CriticalNet; cn; cn = cn->next) { if (Verbose > 1) Fprintf(stdout, "critical net %s\n", cn->name); for (j = 0; j < Numnets; j++) { net = Nlnets[j]; if (!strcmp(net->netname, (char *)cn->name)) { net->netorder = i++; net->flags |= NET_CRITICAL; } } } switch (method) { case 0: qsort((char *)Nlnets, Numnets, (int)sizeof(NET), (__compar_fn_t)compNets); break; case 1: qsort((char *)Nlnets, Numnets, (int)sizeof(NET), (__compar_fn_t)altCompNets); break; } for (i = 0; i < Numnets; i++) { net = Nlnets[i]; net->netorder = i++; } } /* create_netorder() */ /*--------------------------------------------------------------*/ /* Measure and record the bounding box of a net. */ /* This is preparatory to generating a mask for the net. */ /* Find the bounding box of each node, and record that */ /* information, at the same time computing the whole net's */ /* bounding box as the area bounding all of the nodes. */ /* Determine if the bounding box is more horizontal or */ /* vertical, and specify a direction for the net's trunk line. */ /* Initialize the trunk line as the midpoint between all of the */ /* nodes, extending the width (or height) of the bounding box. */ /* Initialize the node branch position as the line extending */ /* from the middle of the node's bounding box to the trunk */ /* line. These positions (trunk and branches) will be sorted */ /* and readjusted by "create_nodeorder()". */ /*--------------------------------------------------------------*/ void find_bounding_box(NET net) { NODE n1, n2; DPOINT d1tap, d2tap, dtap, mintap; int mindist, dist, dx, dy; if (net->numnodes == 2) { n1 = (NODE)net->netnodes; n2 = (NODE)net->netnodes->next; // Simple 2-pass---pick up first tap on n1, find closest tap on n2, // then find closest tap on n1. d1tap = (n1->taps == NULL) ? n1->extend : n1->taps; if (d1tap == NULL) return; d2tap = (n2->taps == NULL) ? n2->extend : n2->taps; if (d2tap == NULL) return; dx = d2tap->gridx - d1tap->gridx; dy = d2tap->gridy - d1tap->gridy; mindist = dx * dx + dy * dy; mintap = d2tap; for (d2tap = d2tap->next; d2tap != NULL; d2tap = d2tap->next) { dx = d2tap->gridx - d1tap->gridx; dy = d2tap->gridy - d1tap->gridy; dist = dx * dx + dy * dy; if (dist < mindist) { mindist = dist; mintap = d2tap; } } d2tap = mintap; d1tap = (n1->taps == NULL) ? n1->extend : n1->taps; dx = d2tap->gridx - d1tap->gridx; dy = d2tap->gridy - d1tap->gridy; mindist = dx * dx + dy * dy; mintap = d1tap; for (d1tap = d1tap->next; d1tap != NULL; d1tap = d1tap->next) { dx = d2tap->gridx - d1tap->gridx; dy = d2tap->gridy - d1tap->gridy; dist = dx * dx + dy * dy; if (dist < mindist) { mindist = dist; mintap = d1tap; } } d1tap = mintap; net->xmin = (d1tap->gridx < d2tap->gridx) ? d1tap->gridx : d2tap->gridx; net->xmax = (d1tap->gridx < d2tap->gridx) ? d2tap->gridx : d1tap->gridx; net->ymin = (d1tap->gridy < d2tap->gridy) ? d1tap->gridy : d2tap->gridy; net->ymax = (d1tap->gridy < d2tap->gridy) ? d2tap->gridy : d1tap->gridy; } else { // Net with more than 2 nodes // Use the first tap point for each node to get a rough bounding box and // centroid of all taps net->xmax = net->ymax = -(MAXRT); net->xmin = net->ymin = MAXRT; for (n1 = net->netnodes; n1 != NULL; n1 = n1->next) { dtap = (n1->taps == NULL) ? n1->extend : n1->taps; if (dtap) { if (dtap->gridx > net->xmax) net->xmax = dtap->gridx; if (dtap->gridx < net->xmin) net->xmin = dtap->gridx; if (dtap->gridy > net->ymax) net->ymax = dtap->gridy; if (dtap->gridy < net->ymin) net->ymin = dtap->gridy; } } } } /*--------------------------------------------------------------*/ /* defineRouteTree() --- */ /* */ /* Define a trunk-and-branches potential best route for a net. */ /* */ /* The net is analyzed for aspect ratio, and is determined if */ /* it will have a horizontal or vertical trunk. Then, each */ /* node will define a branch line extending from the node */ /* position to the trunk. Trunk position is recorded in the */ /* net record, and branch positions are recorded in the node */ /* records. */ /* */ /* To do: */ /* Trunk and branch lines will be analyzed for immediate */ /* collisions and sorted to help ensure a free track exists for */ /* each net's trunk line. */ /*--------------------------------------------------------------*/ void defineRouteTree(NET net) { NODE n1; DPOINT dtap; int xcent, ycent, xmin, ymin, xmax, ymax; // This is called after create_bounding_box(), so bounds have // been calculated. xmin = net->xmin; xmax = net->xmax; ymin = net->ymin; ymax = net->ymax; if (net->numnodes == 2) { // For 2-node nets, record the initial position as // one horizontal trunk + one branch for one "L" of // the bounding box, and one vertical trunk + one // branch for the other "L" of the bounding box. net->trunkx = xmin; net->trunky = ymin; } else if (net->numnodes > 0) { // Use the first tap point for each node to get a rough // centroid of all taps xcent = ycent = 0; for (n1 = net->netnodes; n1 != NULL; n1 = n1->next) { dtap = (n1->taps == NULL) ? n1->extend : n1->taps; if (dtap == NULL) continue; xcent += dtap->gridx; ycent += dtap->gridy; } xcent /= net->numnodes; ycent /= net->numnodes; // Record the trunk line in the net record net->trunkx = xcent; net->trunky = ycent; } if (xmax - xmin > ymax - ymin) { // Horizontal trunk preferred net->flags &= ~NET_VERTICAL_TRUNK; } else { // Vertical trunk preferred net->flags |= NET_VERTICAL_TRUNK; } // Set the branch line positions to the node tap points for (n1 = net->netnodes; n1; n1 = n1->next) { dtap = (n1->taps == NULL) ? n1->extend : n1->taps; if (!dtap) continue; n1->branchx = dtap->gridx; n1->branchy = dtap->gridy; } } /*--------------------------------------------------------------*/ /* print_nodes - show the nodes list */ /* ARGS: filename to print to RETURNS: nothing SIDE EFFECTS: none AUTHOR and DATE: steve beccue Tue Aug 04 2003 \*--------------------------------------------------------------*/ void print_nodes(char *filename) { FILE *o; int i, j; NET net; NODE node; DPOINT dp; if (!strcmp(filename, "stdout")) { o = stdout; } else { o = fopen(filename, "w"); } if (!o) { Fprintf( stderr, "node.c:print_nodes. Couldn't open output file\n" ); return; } for (i = 0; i < Numnets; i++) { net = Nlnets[i]; for (node = net->netnodes; node; node = node->next) { dp = (DPOINT)node->taps; fprintf(o, "%d\t%s\t(%g,%g)(%d,%d) :%d:num=%d netnum=%d\n", node->nodenum, node->netname, // legacy: print only the first point dp->x, dp->y, dp->gridx, dp->gridy, node->netnum, node->numnodes, node->netnum ); /* need to print the routes to this node (deprecated) for (j = 0 ; j < g->nodes; j++) { fprintf(o, "%s(%g,%g) ", g->node[j], *(g->x[j]), *(g->y[j])); } */ } } fclose(o); } /* void print_nodes() */ /*--------------------------------------------------------------*/ /*C print_nlnets - show the nets */ /* ARGS: filename to print to RETURNS: nothing SIDE EFFECTS: none AUTHOR and DATE: steve beccue Tue Aug 04 2003 \*--------------------------------------------------------------*/ void print_nlnets( char *filename ) { FILE *o; int i; NODE nd; NET net; if (!strcmp(filename, "stdout")) { o = stdout; } else { o = fopen(filename, "w"); } if (!o) { Fprintf(stderr, "node.c:print_nlnets. Couldn't open output file\n"); return; } for (i = 0; i < Numnets; i++) { net = Nlnets[i]; fprintf(o, "%d\t#=%d\t%s \t\n", net->netnum, net->numnodes, net->netname); for (nd = net->netnodes; nd; nd = nd->next) { fprintf(o, "%d ", nd->nodenum); } } fprintf(o, "%d nets\n", Numnets); fflush(o); } /* void print_nlnets() */ /*--------------------------------------------------------------*/ /* count_reachable_taps() */ /* */ /* For each grid point in the layout, find if it corresponds */ /* to a node and is unobstructed. If so, increment the node's */ /* count of reachable taps. Then work through the list of */ /* nodes and determine if any are completely unreachable. If */ /* so, then unobstruct any position that is inside tap */ /* geometry that can contain a via. */ /* */ /* NOTE: This routine should check for tap rectangles that */ /* may combine to form an area large enough to place a via; */ /* also, it should check for tap points that are routable */ /* by a wire and not a tap. However, those conditions are */ /* rare and are left unhandled for now. */ /*--------------------------------------------------------------*/ void count_reachable_taps() { NODE node; GATE g; DSEG ds; int l, i, j; int gridx, gridy; double deltax, deltay; double dx, dy; for (l = 0; l < Num_layers; l++) { for (j = 0; j < NumChannelsX[l] * NumChannelsY[l]; j++) { node = Nodeloc[l][j]; if (node != NULL) { // Redundant check; if Obs has NO_NET set, then // Nodeloc for that position should already be NULL if (!(Obs[l][j] & NO_NET)) node->numtaps++; } } } for (g = Nlgates; g; g = g->next) { for (i = 0; i < g->nodes; i++) { node = g->noderec[i]; if (node == NULL) continue; if (node->numnodes == 0) continue; // e.g., vdd or gnd bus if (node->numtaps == 0) { Fprintf(stderr, "Error: Node %s of net \"%s\" has no taps!\n", print_node_name(node), node->netname); for (ds = g->taps[i]; ds; ds = ds->next) { deltax = 0.5 * LefGetViaWidth(ds->layer, ds->layer, 0); deltay = 0.5 * LefGetViaWidth(ds->layer, ds->layer, 1); gridx = (int)((ds->x1 - Xlowerbound) / PitchX[ds->layer]) - 1; while (1) { dx = (gridx * PitchX[ds->layer]) + Xlowerbound; if (dx > ds->x2 || gridx >= NumChannelsX[ds->layer]) break; if (((dx - ds->x1 + EPS) > deltax) && ((ds->x2 - dx + EPS) > deltax)) { gridy = (int)((ds->y1 - Ylowerbound) / PitchY[ds->layer]) - 1; while (1) { dy = (gridy * PitchY[ds->layer]) + Ylowerbound; if (dy > ds->y2 || gridy >= NumChannelsY[ds->layer]) break; if (((dy - ds->y1 + EPS) > deltay) && ((ds->y2 - dy + EPS) > deltay)) { if ((ds->layer == Num_layers - 1) || !(Obs[ds->layer + 1][OGRID(gridx, gridy, ds->layer + 1)] & NO_NET)) { // Grid position is clear for placing a via Fprintf(stderr, "Tap position (%g, %g) appears" " to be technically routable, so it" " is being forced routable.\n", dx, dy); Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] = (Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] & BLOCKED_MASK) | (u_int)node->netnum; Nodeloc[ds->layer][OGRID(gridx, gridy, ds->layer)] = node; Nodesav[ds->layer][OGRID(gridx, gridy, ds->layer)] = node; node->numtaps++; } } gridy++; } } gridx++; } } } if (node->numtaps == 0) { Fprintf(stderr, "Qrouter will not be able to completely" " route this net.\n"); } } } } /*--------------------------------------------------------------*/ /* check_variable_pitch() */ /* */ /* This routine is used by the routine below it to generate */ /* obstructions that force routes to be placed in 1-of-N */ /* tracks. However, it is also used to determine the same */ /* information for the .info file, so that the effective */ /* pitch is output, not the pitch copied from the LEF file. */ /* Output is the vertical and horizontal pitch multipliers, */ /* passed back through pointers. */ /*--------------------------------------------------------------*/ void check_variable_pitch(int l, int *hptr, int *vptr) { int o, hnum, vnum; double vpitch, hpitch, wvia; o = LefGetRouteOrientation(l); // Pick the best via size for the layer. Usually this means the // via whose base is at layer - 1, because the top metal layer // will either have the same width or a larger width. // Note that when "horizontal" (o = 1) is passed to LefGetViaWidth, // it returns the via width side-to-side; but for horizontal routing // the dimension of interest is the height of the via. Therefore // the direction argument passed to LefGetViaWidth is (1 - o). if (l == 0) wvia = LefGetViaWidth(l, l, (1 - o)); else wvia = LefGetViaWidth(l - 1, l, (1 - o)); if (o == 1) { // Horizontal route vpitch = LefGetRoutePitch(l); // Changed: routes must be able to accomodate the placement // of a via in the track next to it. // hpitch = LefGetRouteWidth(l) + LefGetRouteSpacing(l); hpitch = 0.5 * (LefGetRouteWidth(l) + wvia) + LefGetRouteSpacing(l); } else { // Vertical route hpitch = LefGetRoutePitch(l); // vpitch = LefGetRouteWidth(l) + LefGetRouteSpacing(l); vpitch = 0.5 * (LefGetRouteWidth(l) + wvia) + LefGetRouteSpacing(l); } vnum = 1; while (vpitch > PitchY[l] + EPS) { vpitch /= 2.0; vnum++; } hnum = 1; while (hpitch > PitchX[l] + EPS) { hpitch /= 2.0; hnum++; } *vptr = vnum; *hptr = hnum; } /*--------------------------------------------------------------*/ /* create_obstructions_from_variable_pitch() */ /* */ /* Although it would be nice to have an algorithm that would */ /* work with any arbitrary pitch, qrouter will work around */ /* having larger pitches on upper metal layers by selecting */ /* 1 out of every N tracks for routing, and placing */ /* obstructions in the interstices. This makes the possibly */ /* unwarranted assumption that the contact down to the layer */ /* below does not cause spacing violations to neighboring */ /* tracks. If that assumption fails, this routine will have */ /* to be revisited. */ /*--------------------------------------------------------------*/ void create_obstructions_from_variable_pitch() { int l, vnum, hnum, x, y; for (l = 0; l < Num_layers; l++) { check_variable_pitch(l, &hnum, &vnum); // This could be better handled by restricting // access from specific directions rather than // marking a position as NO_NET. Since the // routine below will mark no positions restricted // if either hnum is 1 or vnum is 1, regardless of // the other value, then we force both values to // be at least 2. if (vnum > 1 && hnum == 1) hnum++; if (hnum > 1 && vnum == 1) vnum++; if (vnum > 1 || hnum > 1) { for (x = 0; x < NumChannelsX[l]; x++) { if (x % hnum == 0) continue; for (y = 0; y < NumChannelsY[l]; y++) { if (y % vnum == 0) continue; // If the grid position itself is a node, don't restrict // routing based on variable pitch. if (Nodeloc[l][OGRID(x, y, l)] != NULL) continue; // If there is a node in an adjacent grid then allow // routing from that direction. if ((x > 0) && Nodeloc[l][OGRID(x - 1, y, l)] != NULL) Obs[l][OGRID(x, y, l)] = BLOCKED_MASK & ~BLOCKED_W; else if ((y > 0) && Nodeloc[l][OGRID(x , y - 1, l)] != NULL) Obs[l][OGRID(x, y, l)] = BLOCKED_MASK & ~BLOCKED_S; else if ((x < NumChannelsX[l] - 1) && Nodeloc[l][OGRID(x + 1, y, l)] != NULL) Obs[l][OGRID(x, y, l)] = BLOCKED_MASK & ~BLOCKED_E; else if ((y < NumChannelsY[l] - 1) && Nodeloc[l][OGRID(x, y + 1, l)] != NULL) Obs[l][OGRID(x, y, l)] = BLOCKED_MASK & ~BLOCKED_N; else Obs[l][OGRID(x, y, l)] = NO_NET; } } } } } /*--------------------------------------------------------------*/ /* disable_gridpos() --- */ /* Render the position at (x, y, lay) unroutable by */ /* setting its Obs[] entry to NO_NET and removing it from */ /* the Nodeloc and Nodesav records. */ /*--------------------------------------------------------------*/ void disable_gridpos(int x, int y, int lay) { int apos = OGRID(x, y, lay); Obs[lay][apos] = (u_int)(NO_NET | OBSTRUCT_MASK); Nodeloc[lay][apos] = NULL; Nodesav[lay][apos] = NULL; Stub[lay][apos] = 0.0; } /*--------------------------------------------------------------*/ /* count_pinlayers()--- */ /* Check which layers have non-NULL Nodeloc, Nodesav, and */ /* Stub entries. Then set "Pinlayers" and free all the */ /* unused layers. This saves a lot of memory, especially */ /* when the number of routing layers becomes large. */ /*--------------------------------------------------------------*/ void count_pinlayers() { int j, l; Pinlayers = 0; for (l = 0; l < Num_layers; l++) { for (j = 0; j < NumChannelsX[l] * NumChannelsY[l]; j++) { if (Nodesav[l][j] != NULL) { Pinlayers = l + 1; break; } } } for (l = Pinlayers; l < Num_layers; l++) { free(Stub[l]); free(Nodeloc[l]); free(Nodesav[l]); Stub[l] = NULL; Nodeloc[l] = NULL; Nodesav[l] = NULL; } } /*--------------------------------------------------------------*/ /* check_obstruct()--- */ /* Called from create_obstructions_from_gates(), this */ /* routine takes a grid point at (gridx, gridy) (physical */ /* position (dx, dy)) and an obstruction defined by the */ /* rectangle "ds", and sets flags and fills the Obsinfo */ /* array to reflect how the obstruction affects routing to */ /* the grid position. */ /*--------------------------------------------------------------*/ void check_obstruct(int gridx, int gridy, DSEG ds, double dx, double dy) { int *obsptr; float dist; obsptr = &(Obs[ds->layer][OGRID(gridx, gridy, ds->layer)]); dist = Obsinfo[ds->layer][OGRID(gridx, gridy, ds->layer)]; // Grid point is inside obstruction + halo. *obsptr |= NO_NET; // Completely inside obstruction? if (dy > ds->y1 && dy < ds->y2 && dx > ds->x1 && dx < ds->x2) *obsptr |= OBSTRUCT_MASK; else { // Make more detailed checks in each direction if (dy < ds->y1) { if ((*obsptr & (OBSTRUCT_MASK & ~OBSTRUCT_N)) == 0) { if ((dist == 0) || ((ds->y1 - dy) < dist)) Obsinfo[ds->layer][OGRID(gridx, gridy, ds->layer)] = ds->y1 - dy; *obsptr |= OBSTRUCT_N; } else *obsptr |= OBSTRUCT_MASK; } else if (dy > ds->y2) { if ((*obsptr & (OBSTRUCT_MASK & ~OBSTRUCT_S)) == 0) { if ((dist == 0) || ((dy - ds->y2) < dist)) Obsinfo[ds->layer][OGRID(gridx, gridy, ds->layer)] = dy - ds->y2; *obsptr |= OBSTRUCT_S; } else *obsptr |= OBSTRUCT_MASK; } if (dx < ds->x1) { if ((*obsptr & (OBSTRUCT_MASK & ~OBSTRUCT_E)) == 0) { if ((dist == 0) || ((ds->x1 - dx) < dist)) Obsinfo[ds->layer][OGRID(gridx, gridy, ds->layer)] = ds->x1 - dx; *obsptr |= OBSTRUCT_E; } else *obsptr |= OBSTRUCT_MASK; } else if (dx > ds->x2) { if ((*obsptr & (OBSTRUCT_MASK & ~OBSTRUCT_W)) == 0) { if ((dist == 0) || ((dx - ds->x2) < dist)) Obsinfo[ds->layer][OGRID(gridx, gridy, ds->layer)] = dx - ds->x2; *obsptr |= OBSTRUCT_W; } else *obsptr |= OBSTRUCT_MASK; } } } /*--------------------------------------------------------------*/ /* Find the amount of clearance needed between an obstruction */ /* and a route track position. This takes into consideration */ /* whether the obstruction is wide or narrow metal, if the */ /* spacing rules are graded according to metal width, and if a */ /* via placed at the position is or is not symmetric in X and Y */ /*--------------------------------------------------------------*/ double get_via_clear(int lay, int horiz, DSEG rect) { double vdelta, v2delta, mdelta, mwidth; vdelta = LefGetViaWidth(lay, lay, 1 - horiz); if (lay > 0) { v2delta = LefGetViaWidth(lay - 1, lay, 1 - horiz); if (v2delta > vdelta) vdelta = v2delta; } vdelta = vdelta / 2.0; // Spacing rule is determined by the minimum metal width, // either in X or Y, regardless of the position of the // metal being checked. mwidth = MIN(rect->x2 - rect->x1, rect->y2 - rect->y1); mdelta = LefGetRouteWideSpacing(lay, mwidth); return vdelta + mdelta; } /*--------------------------------------------------------------*/ /* Find the distance from an obstruction to a grid point, */ /* considering only routes which are placed at the position, */ /* not vias. */ /*--------------------------------------------------------------*/ double get_route_clear(int lay, DSEG rect) { double rdelta, mdelta, mwidth; rdelta = LefGetRouteWidth(lay); rdelta = rdelta / 2.0; // Spacing rule is determined by the minimum metal width, // either in X or Y, regardless of the position of the // metal being checked. mwidth = MIN(rect->x2 - rect->x1, rect->y2 - rect->y1); mdelta = LefGetRouteWideSpacing(lay, mwidth); return rdelta + mdelta; } /*--------------------------------------------------------------*/ /* create_obstructions_from_gates() */ /* */ /* Fills in the Obs[][] grid from obstructions that were */ /* defined for each macro in the technology LEF file and */ /* translated into a list of grid coordinates in each */ /* instance. */ /* */ /* Also, fills in the Obs[][] grid with obstructions that */ /* are defined by nodes of the gate that are unconnected in */ /* this netlist. */ /*--------------------------------------------------------------*/ void create_obstructions_from_gates() { GATE g; DSEG ds; int i, gridx, gridy, *obsptr; double deltax, deltay, delta[MAX_LAYERS]; double dx, dy, deltaxy; float dist; // Give a single net number to all obstructions, over the range of the // number of known nets, so these positions cannot be routed through. // If a grid position is not wholly inside an obstruction, then we // maintain the direction of the nearest obstruction in Obs and the // distance to it in Obsinfo. This indicates that a route can avoid // the obstruction by moving away from it by the amount in Obsinfo // plus spacing clearance. If another obstruction is found that // prevents such a move, then all direction flags will be set, indicating // that the position is not routable under any condition. for (g = Nlgates; g; g = g->next) { for (ds = g->obs; ds; ds = ds->next) { deltax = get_via_clear(ds->layer, 1, ds); gridx = (int)((ds->x1 - Xlowerbound - deltax) / PitchX[ds->layer]) - 1; while (1) { dx = (gridx * PitchX[ds->layer]) + Xlowerbound; if ((dx + EPS) > (ds->x2 + deltax) || gridx >= NumChannelsX[ds->layer]) break; else if ((dx - EPS) > (ds->x1 - deltax) && gridx >= 0) { deltay = get_via_clear(ds->layer, 0, ds); gridy = (int)((ds->y1 - Ylowerbound - deltay) / PitchY[ds->layer]) - 1; while (1) { dy = (gridy * PitchY[ds->layer]) + Ylowerbound; if ((dy + EPS) > (ds->y2 + deltay) || gridy >= NumChannelsY[ds->layer]) break; if ((dy - EPS) > (ds->y1 - deltay) && gridy >= 0) { double s, edist, xp, yp; // Check Euclidean distance measure s = LefGetRouteSpacing(ds->layer); if (dx < (ds->x1 + s - deltax)) { xp = dx + deltax - s; edist = (ds->x1 - xp) * (ds->x1 - xp); } else if (dx > (ds->x2 - s + deltax)) { xp = dx - deltax + s; edist = (xp - ds->x2) * (xp - ds->x2); } else edist = 0; if ((edist > 0) && (dy < (ds->y1 + s - deltay))) { yp = dy + deltay - s; edist += (ds->y1 - yp) * (ds->y1 - yp); } else if ((edist > 0) && (dy > (ds->y2 - s + deltay))) { yp = dy - deltay + s; edist += (yp - ds->y2) * (yp - ds->y2); } else edist = 0; if ((edist + EPS) < (s * s)) { // If it clears distance for a route layer but not // vias, then block vias only. deltaxy = get_route_clear(ds->layer, ds); if (((dx - EPS) <= (ds->x1 - deltaxy)) || ((dx + EPS) >= (ds->x2 + deltaxy)) || ((dy - EPS) <= (ds->y1 - deltaxy)) || ((dy + EPS) >= (ds->y2 + deltaxy))) { block_route(gridx, gridy, ds->layer, UP); block_route(gridx, gridy, ds->layer, DOWN); } else check_obstruct(gridx, gridy, ds, dx, dy); } else { edist = 0; // diagnostic break } } gridy++; } } gridx++; } } for (i = 0; i < g->nodes; i++) { if (g->netnum[i] == 0) { /* Unconnected node */ // Diagnostic, and power bus handling if (g->node[i]) { // Should we flag a warning if we see something that looks // like a power or ground net here? if (Verbose > 1) Fprintf(stdout, "Gate instance %s unconnected node %s\n", g->gatename, g->node[i]); } else { if (Verbose > 1) Fprintf(stdout, "Gate instance %s unconnected node (%d)\n", g->gatename, i); } for (ds = g->taps[i]; ds; ds = ds->next) { deltax = get_via_clear(ds->layer, 1, ds); gridx = (int)((ds->x1 - Xlowerbound - deltax) / PitchX[ds->layer]) - 1; while (1) { dx = (gridx * PitchX[ds->layer]) + Xlowerbound; if (dx > (ds->x2 + deltax) || gridx >= NumChannelsX[ds->layer]) break; else if (dx >= (ds->x1 - deltax) && gridx >= 0) { deltay = get_via_clear(ds->layer, 0, ds); gridy = (int)((ds->y1 - Ylowerbound - deltay) / PitchY[ds->layer]) - 1; while (1) { dy = (gridy * PitchY[ds->layer]) + Ylowerbound; if ((dy + EPS) > (ds->y2 + deltay) || gridy >= NumChannelsY[ds->layer]) break; if ((dy - EPS) >= (ds->y1 - deltay) && gridy >= 0) { double s, edist, xp, yp; // Check Euclidean distance measure s = LefGetRouteSpacing(ds->layer); if (dx < (ds->x1 + s - deltax)) { xp = dx + deltax - s; edist += (ds->x1 - xp) * (ds->x1 - xp); } else if (dx > (ds->x2 - s + deltax)) { xp = dx - deltax + s; edist += (xp - ds->x2) * (xp - ds->x2); } else edist = 0; if ((edist > 0) && (dy < (ds->y1 + s - deltay))) { yp = dy + deltay - s; edist += (ds->y1 - yp) * (ds->y1 - yp); } else if ((edist > 0) && (dy > (ds->y2 - s + deltay))) { yp = dy - deltay + s; edist += (yp - ds->y2) * (yp - ds->y2); } else edist = 0; if ((edist + EPS) < (s * s)) { // If it clears distance for a route layer but not // vias, then block vias only. deltaxy = get_route_clear(ds->layer, ds); if (((dx - EPS) < (ds->x1 - deltaxy)) || ((dx + EPS) > (ds->x2 + deltaxy)) || ((dy - EPS) < (ds->y1 - deltaxy)) || ((dy + EPS) > (ds->y2 + deltaxy))) { block_route(gridx, gridy, ds->layer, UP); block_route(gridx, gridy, ds->layer, DOWN); } else check_obstruct(gridx, gridy, ds, dx, dy); } } gridy++; } } gridx++; } } } } } // Create additional obstructions from the UserObs list // These obstructions are not considered to be metal layers, // so we don't compute a distance measure. However, we need // to compute a boundary of 1/2 route width to avoid having // the route overlapping the obstruction area. for (i = 0; i < Num_layers; i++) { delta[i] = LefGetRouteWidth(i) / 2.0; } for (ds = UserObs; ds; ds = ds->next) { gridx = (int)((ds->x1 - Xlowerbound - delta[ds->layer]) / PitchX[ds->layer]) - 1; while (1) { dx = (gridx * PitchX[ds->layer]) + Xlowerbound; if (dx > (ds->x2 + delta[ds->layer]) || gridx >= NumChannelsX[ds->layer]) break; else if (dx >= (ds->x1 - delta[ds->layer]) && gridx >= 0) { gridy = (int)((ds->y1 - Ylowerbound - delta[ds->layer]) / PitchY[ds->layer]) - 1; while (1) { dy = (gridy * PitchY[ds->layer]) + Ylowerbound; if (dy > (ds->y2 + delta[ds->layer]) || gridy >= NumChannelsY[ds->layer]) break; if (dy >= (ds->y1 - delta[ds->layer]) && gridy >= 0) check_obstruct(gridx, gridy, ds, dx, dy); gridy++; } } gridx++; } } } /*--------------------------------------------------------------*/ /* expand_tap_geometry() */ /* */ /* For each rectangle defining part of a gate terminal, */ /* search the surrounding terminal geometry. If the rectangle */ /* can expand in any direction, then allow it to grow to the */ /* maximum size. This generates overlapping geometry for each */ /* terminal, but avoids bad results for determining how to */ /* route to a terminal point if the terminal is broken up into */ /* numerous nonoverlapping rectangles. */ /* */ /* Note that this is not foolproof. It also needs a number of */ /* enhancements. For example, to expand east, other geometry */ /* should be looked at in order of increasing left edge X */ /* value, and so forth. */ /*--------------------------------------------------------------*/ void expand_tap_geometry() { DSEG ds, ds2; GATE g; int i; u_char expanded; for (g = Nlgates; g; g = g->next) { for (i = 0; i < g->nodes; i++) { if (g->netnum[i] == 0) continue; for (ds = g->taps[i]; ds; ds = ds->next) { expanded = TRUE; while (expanded == TRUE) { expanded = FALSE; for (ds2 = g->taps[i]; ds2; ds2 = ds2->next) { if (ds == ds2) continue; if (ds->layer != ds2->layer) continue; if ((ds2->y1 <= ds->y1) && (ds2->y2 >= ds->y2)) { // Expand east if ((ds2->x1 > ds->x1) && (ds2->x1 <= ds->x2)) if (ds->x2 < ds2->x2) { ds->x2 = ds2->x2; expanded = TRUE; } // Expand west if ((ds2->x2 < ds->x2) && (ds2->x2 >= ds->x1)) if (ds->x1 > ds2->x1) { ds->x1 = ds2->x1; expanded = TRUE; } } if ((ds2->x1 <= ds->x1) && (ds2->x2 >= ds->x2)) { // Expand north if ((ds2->y1 > ds->y1) && (ds2->y1 <= ds->y2)) if (ds->y2 < ds2->y2) { ds->y2 = ds2->y2; expanded = TRUE; } // Expand south if ((ds2->y2 < ds->y2) && (ds2->y2 >= ds->y1)) if (ds->y1 > ds2->y1) { ds->y1 = ds2->y1; expanded = TRUE; } } } } } } } } /*--------------------------------------------------------------*/ /* create_obstructions_inside_nodes() */ /* */ /* Fills in the Obs[][] grid from the position of each node */ /* (net terminal), which may have multiple unconnected */ /* positions. */ /* */ /* Also fills in the Nodeloc[] grid with the node number, */ /* which causes the router to put a premium on */ /* routing other nets over or under this position, to */ /* discourage boxing in a pin position and making it */ /* unroutable. */ /* */ /* This routine is split into two passes. This pass adds */ /* information for points inside node regions. */ /* */ /* ARGS: none. */ /* RETURNS: nothing */ /* SIDE EFFECTS: none */ /* AUTHOR: Tim Edwards, June 2011, based on code by Steve */ /* Beccue. */ /*--------------------------------------------------------------*/ void create_obstructions_inside_nodes() { NODE node, n2; GATE g; DPOINT dp; DSEG ds; u_int dir, k; int i, gx, gy, gridx, gridy, net; double dx, dy, deltax, deltay; float dist, xdist; double offmaxx[MAX_LAYERS], offmaxy[MAX_LAYERS]; // Use a more conservative definition of keepout, to include via // widths, which may be bigger than route widths. for (i = 0; i < Num_layers; i++) { offmaxx[i] = PitchX[i] - LefGetRouteSpacing(i) - 0.5 * (LefGetRouteWidth(i) + LefGetViaWidth(i, i, 0)); offmaxy[i] = PitchY[i] - LefGetRouteSpacing(i) - 0.5 * (LefGetRouteWidth(i) + LefGetViaWidth(i, i, 1)); } // When we place vias at an offset, they have to satisfy the spacing // requirements for the via's top layer, as well. So take the least // maximum offset of each layer and the layer above it. for (i = 0; i < Num_layers - 1; i++) { offmaxx[i] = MIN(offmaxx[i], offmaxx[i + 1]); offmaxy[i] = MIN(offmaxy[i], offmaxy[i + 1]); } // For each node terminal (gate pin), mark each grid position with the // net number. This overrides any obstruction that may be placed at that // point. // For each pin position, we also find the "keepout" area around the // pin where we may not place an unrelated route. For this, we use a // flag bit, so that the position can be ignored when routing the net // associated with the pin. Normal obstructions take precedence. for (g = Nlgates; g; g = g->next) { for (i = 0; i < g->nodes; i++) { if (g->netnum[i] != 0) { // Get the node record associated with this pin. node = g->noderec[i]; if (node == NULL) continue; // First mark all areas inside node geometry boundary. for (ds = g->taps[i]; ds; ds = ds->next) { gridx = (int)((ds->x1 - Xlowerbound) / PitchX[ds->layer]) - 1; while (1) { dx = (gridx * PitchX[ds->layer]) + Xlowerbound; if (dx > ds->x2 || gridx >= NumChannelsX[ds->layer]) break; else if (dx >= ds->x1 && gridx >= 0) { gridy = (int)((ds->y1 - Ylowerbound) / PitchY[ds->layer]) - 1; while (1) { dy = (gridy * PitchY[ds->layer]) + Ylowerbound; if (dy > ds->y2 || gridy >= NumChannelsY[ds->layer]) break; // Area inside defined pin geometry if (dy > ds->y1 && gridy >= 0) { int orignet = Obs[ds->layer][OGRID(gridx, gridy, ds->layer)]; if ((orignet & ROUTED_NET_MASK) == (u_int)node->netnum) { // Duplicate tap point. Don't re-process it. (?) gridy++; continue; } if (!(orignet & NO_NET) && ((orignet & ROUTED_NET_MASK) != (u_int)0)) { // Net was assigned to other net, but is inside // this pin's geometry. Declare point to be // unroutable, as it is too close to both pins. // NOTE: This is a conservative rule and could // potentially make a pin unroutable. // Another note: By setting Obs[] to // OBSTRUCT_MASK as well as NO_NET, we ensure // that it falls through on all subsequent // processing. disable_gridpos(gridx, gridy, ds->layer); } else if (!(orignet & NO_NET)) { // A grid point that is within 1/2 route width // of a tap rectangle corner can violate metal // width rules, and so should declare a stub. dir = 0; dist = 0.0; xdist = 0.5 * LefGetRouteWidth(ds->layer); if (dx >= ds->x2 - xdist) { if (dy > ds->y2 - xdist + EPS) { // Check northeast corner if ((ds->x2 - dx) > (ds->y2 - dy)) { // West-pointing stub dir = STUBROUTE_EW; dist = ds->x2 - dx - 2.0 * xdist; } else { // South-pointing stub dir = STUBROUTE_NS; dist = ds->y2 - dy - 2.0 * xdist; } } else if (dy < ds->y1 + xdist - EPS) { // Check southeast corner if ((ds->x2 - dx) > (dy - ds->y1)) { // West-pointing stub dir = STUBROUTE_EW; dist = ds->x2 - dx - 2.0 * xdist; } else { // North-pointing stub dir = STUBROUTE_NS; dist = ds->y1 - dy + 2.0 * xdist; } } } else if (dx <= ds->x1 + xdist) { if (dy > ds->y2 - xdist + EPS) { // Check northwest corner if ((dx - ds->x1) > (ds->y2 - dy)) { // East-pointing stub dir = STUBROUTE_EW; dist = ds->x1 - dx + 2.0 * xdist; } else { // South-pointing stub dir = STUBROUTE_NS; dist = ds->y2 - dy - 2.0 * xdist; } } else if (dy < ds->y1 + xdist - EPS) { // Check southwest corner if ((dx - ds->x2) > (dy - ds->y1)) { // East-pointing stub dir = STUBROUTE_EW; dist = ds->x1 - dx + 2.0 * xdist; } else { // North-pointing stub dir = STUBROUTE_NS; dist = ds->y1 - dy + 2.0 * xdist; } } } Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] = (Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] & BLOCKED_MASK) | (u_int)node->netnum | dir; Nodeloc[ds->layer][OGRID(gridx, gridy, ds->layer)] = node; Nodesav[ds->layer][OGRID(gridx, gridy, ds->layer)] = node; Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = dist; } else if ((orignet & NO_NET) && ((orignet & OBSTRUCT_MASK) != OBSTRUCT_MASK)) { /* Handled on next pass */ } // Check that we have not created a PINOBSTRUCT // route directly over this point. if (ds->layer < Num_layers - 1) { k = Obs[ds->layer + 1][OGRID(gridx, gridy, ds->layer + 1)]; if (k & PINOBSTRUCTMASK) { if ((k & ROUTED_NET_MASK) != (u_int)node->netnum) { Obs[ds->layer + 1][OGRID(gridx, gridy, ds->layer + 1)] = NO_NET; Nodeloc[ds->layer + 1][OGRID(gridx, gridy, ds->layer + 1)] = (NODE)NULL; Nodesav[ds->layer + 1][OGRID(gridx, gridy, ds->layer + 1)] = (NODE)NULL; Stub[ds->layer + 1][OGRID(gridx, gridy, ds->layer + 1)] = (float)0.0; } } } } gridy++; } } gridx++; } } } } } } /* void create_obstructions_inside_nodes( void ) */ /*--------------------------------------------------------------*/ /* create_obstructions_outside_nodes() */ /* */ /* Fills in the Obs[][] grid from the position of each node */ /* (net terminal), which may have multiple unconnected */ /* positions. */ /* */ /* Also fills in the Nodeloc[] grid with the node number, */ /* which causes the router to put a premium on */ /* routing other nets over or under this position, to */ /* discourage boxing in a pin position and making it */ /* unroutable. */ /* */ /* This routine is split into two passes. This pass adds */ /* information for points outside node regions but close */ /* enough to interact with the node. */ /* */ /* ARGS: none. */ /* RETURNS: nothing */ /* SIDE EFFECTS: none */ /* AUTHOR: Tim Edwards, June 2011, based on code by Steve */ /* Beccue. */ /*--------------------------------------------------------------*/ void create_obstructions_outside_nodes() { NODE node, n2; GATE g; DPOINT dp; DSEG ds; u_int dir, k; int i, gx, gy, gridx, gridy, net; double dx, dy, deltax, deltay; float dist, xdist; double offmaxx[MAX_LAYERS], offmaxy[MAX_LAYERS]; // Use a more conservative definition of keepout, to include via // widths, which may be bigger than route widths. for (i = 0; i < Num_layers; i++) { offmaxx[i] = PitchX[i] - LefGetRouteSpacing(i) - 0.5 * (LefGetRouteWidth(i) + LefGetViaWidth(i, i, 0)); offmaxy[i] = PitchY[i] - LefGetRouteSpacing(i) - 0.5 * (LefGetRouteWidth(i) + LefGetViaWidth(i, i, 1)); } // When we place vias at an offset, they have to satisfy the spacing // requirements for the via's top layer, as well. So take the least // maximum offset of each layer and the layer above it. for (i = 0; i < Num_layers - 1; i++) { offmaxx[i] = MIN(offmaxx[i], offmaxx[i + 1]); offmaxy[i] = MIN(offmaxy[i], offmaxy[i + 1]); } // For each node terminal (gate pin), mark each grid position with the // net number. This overrides any obstruction that may be placed at that // point. // For each pin position, we also find the "keepout" area around the // pin where we may not place an unrelated route. For this, we use a // flag bit, so that the position can be ignored when routing the net // associated with the pin. Normal obstructions take precedence. for (g = Nlgates; g; g = g->next) { for (i = 0; i < g->nodes; i++) { if (g->netnum[i] != 0) { // Get the node record associated with this pin. node = g->noderec[i]; if (node == NULL) continue; // Repeat this whole exercise for areas in the halo outside // the node geometry. We have to do this after enumerating // all inside areas because the tap rectangles often overlap, // and one rectangle's halo may be inside another tap. for (ds = g->taps[i]; ds; ds = ds->next) { // Note: Should be handling get_route_clear as a less // restrictive case, as was done above. deltax = get_via_clear(ds->layer, 1, ds); gridx = (int)((ds->x1 - Xlowerbound - deltax) / PitchX[ds->layer]) - 1; while (1) { dx = (gridx * PitchX[ds->layer]) + Xlowerbound; if ((dx + EPS) > (ds->x2 + deltax) || gridx >= NumChannelsX[ds->layer]) break; else if ((dx - EPS) > (ds->x1 - deltax) && gridx >= 0) { deltay = get_via_clear(ds->layer, 0, ds); gridy = (int)((ds->y1 - Ylowerbound - deltay) / PitchY[ds->layer]) - 1; while (1) { dy = (gridy * PitchY[ds->layer]) + Ylowerbound; if ((dy + EPS) > (ds->y2 + deltay) || gridy >= NumChannelsY[ds->layer]) break; // 2nd pass on area inside defined pin geometry, // allowing terminal connections to be made using // an offset tap, where possible. if (dy > ds->y1 && gridy >= 0) { int orignet = Obs[ds->layer][OGRID(gridx, gridy, ds->layer)]; if ((orignet & ROUTED_NET_MASK) == (u_int)node->netnum) { // Duplicate tap point. Don't re-process it. gridy++; continue; } if (!(orignet & NO_NET) && ((orignet & ROUTED_NET_MASK) != (u_int)0)) { /* Do nothing; previously handled */ } else if ((orignet & NO_NET) && ((orignet & OBSTRUCT_MASK) != OBSTRUCT_MASK)) { double sdistx = LefGetViaWidth(ds->layer, ds->layer, 0) / 2.0 + LefGetRouteSpacing(ds->layer); double sdisty = LefGetViaWidth(ds->layer, ds->layer, 1) / 2.0 + LefGetRouteSpacing(ds->layer); double offd; // Define a maximum offset we can have in X or // Y above which the placement of a via will // cause a DRC violation with a wire in the // adjacent route track in the direction of the // offset. int maxerr = 0; // If a cell is positioned off-grid, then a grid // point may be inside a pin and still be unroutable. // The Obsinfo[] array tells where an obstruction is, // if there was only one obstruction in one direction // blocking the grid point. If so, then we set the // Stub[] distance to move the tap away from the // obstruction to resolve the DRC error. // Make sure we have marked this as a node. Nodeloc[ds->layer][OGRID(gridx, gridy, ds->layer)] = node; Nodesav[ds->layer][OGRID(gridx, gridy, ds->layer)] = node; Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] = (Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] & BLOCKED_MASK) | (u_int)node->netnum; if (orignet & OBSTRUCT_N) { offd = -(sdisty - Obsinfo[ds->layer] [OGRID(gridx, gridy, ds->layer)]); if (offd >= -offmaxy[ds->layer]) { Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = offd; Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] |= (STUBROUTE_NS | OFFSET_TAP); /* If position above has obstruction, then */ /* add up/down block to prevent vias. */ if ((ds->layer < Num_layers - 1) && (gridy > 0) && (Obs[ds->layer + 1][OGRID(gridx, gridy - 1, ds->layer + 1)] & OBSTRUCT_MASK)) block_route(gridx, gridy, ds->layer, UP); } else maxerr = 1; } else if (orignet & OBSTRUCT_S) { offd = sdisty - Obsinfo[ds->layer] [OGRID(gridx, gridy, ds->layer)]; if (offd <= offmaxy[ds->layer]) { Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = offd; Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] |= (STUBROUTE_NS | OFFSET_TAP); /* If position above has obstruction, then */ /* add up/down block to prevent vias. */ if ((ds->layer < Num_layers - 1) && (gridy < NumChannelsY[ds->layer + 1] - 1) && (Obs[ds->layer + 1][OGRID(gridx, gridy + 1, ds->layer + 1)] & OBSTRUCT_MASK)) block_route(gridx, gridy, ds->layer, UP); } else maxerr = 1; } else if (orignet & OBSTRUCT_E) { offd = -(sdistx - Obsinfo[ds->layer] [OGRID(gridx, gridy, ds->layer)]); if (offd >= -offmaxx[ds->layer]) { Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = offd; Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] |= (STUBROUTE_EW | OFFSET_TAP); /* If position above has obstruction, then */ /* add up/down block to prevent vias. */ if ((ds->layer < Num_layers - 1) && (gridx > 0) && (Obs[ds->layer + 1][OGRID(gridx - 1, gridy, ds->layer + 1)] & OBSTRUCT_MASK)) block_route(gridx, gridy, ds->layer, UP); } else maxerr = 1; } else if (orignet & OBSTRUCT_W) { offd = sdistx - Obsinfo[ds->layer] [OGRID(gridx, gridy, ds->layer)]; if (offd <= offmaxx[ds->layer]) { Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = offd; Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] |= (STUBROUTE_EW | OFFSET_TAP); /* If position above has obstruction, then */ /* add up/down block to prevent vias. */ if ((ds->layer < Num_layers - 1) && (gridx < NumChannelsX[ds->layer] - 1) && (Obs[ds->layer + 1][OGRID(gridx + 1, gridy, ds->layer + 1)] & OBSTRUCT_MASK)) block_route(gridx, gridy, ds->layer, UP); } else maxerr = 1; } if (maxerr == 1) disable_gridpos(gridx, gridy, ds->layer); // Diagnostic else if (Verbose > 3) Fprintf(stderr, "Port overlaps obstruction" " at grid %d %d, position %g %g\n", gridx, gridy, dx, dy); } } if ((dy - EPS) > (ds->y1 - deltay) && gridy >= 0) { double s, edist, xp, yp; unsigned char epass = 0; // Area inside halo around defined pin geometry. // Exclude areas already processed (areas inside // some pin geometry have been marked with netnum) // Also check that we are not about to define a // route position for a pin on a layer above 0 that // blocks a pin underneath it. // Flag positions that pass a Euclidean distance check. // epass = 1 indicates that position clears a // Euclidean distance measurement. s = LefGetRouteSpacing(ds->layer); if (dx < (ds->x1 + s - deltax)) { xp = dx + deltax - s; edist = (ds->x1 - xp) * (ds->x1 - xp); } else if (dx > (ds->x2 - s + deltax)) { xp = dx - deltax + s; edist = (xp - ds->x2) * (xp - ds->x2); } else edist = 0; if ((edist > 0) && (dy < (ds->y1 + s - deltay))) { yp = dy + deltay - s; edist += (ds->y1 - yp) * (ds->y1 - yp); } else if ((edist > 0) && (dy > (ds->y2 - s + deltay))) { yp = dy - deltay + s; edist += (yp - ds->y2) * (yp - ds->y2); } else edist = 0; if ((edist + EPS) > (s * s)) epass = 1; xdist = 0.5 * LefGetRouteWidth(ds->layer); n2 = NULL; if (ds->layer > 0) n2 = Nodeloc[ds->layer - 1][OGRID(gridx, gridy, ds->layer - 1)]; if (n2 == NULL) n2 = Nodeloc[ds->layer][OGRID(gridx, gridy, ds->layer)]; else { // Watch out for the case where a tap crosses // over a different tap. Don't treat the tap // on top as if it is not there! NODE n3; n3 = Nodeloc[ds->layer][OGRID(gridx, gridy, ds->layer)]; if (n3 != NULL && n3 != node) n2 = n3; } // Ignore my own node. if (n2 == node) n2 = NULL; k = Obs[ds->layer][OGRID(gridx, gridy, ds->layer)]; // In case of a port that is inaccessible from a grid // point, or not completely overlapping it, the // stub information will show how to adjust the // route position to cleanly attach to the port. dir = STUBROUTE_X; dist = 0.0; if (((k & ROUTED_NET_MASK) != (u_int)node->netnum) && (n2 == NULL)) { if ((k & OBSTRUCT_MASK) != 0) { float sdist = Obsinfo[ds->layer][OGRID(gridx, gridy, ds->layer)]; // If the point is marked as close to an // obstruction, we can declare this an // offset tap if we are not on a corner. // Because we cannot define both an offset // and a stub simultaneously, if the distance // to clear the obstruction does not make the // route reach the tap, then we mark the grid // position as unroutable. if (dy >= (ds->y1 - xdist) && dy <= (ds->y2 + xdist)) { if ((dx >= ds->x2) && ((k & OBSTRUCT_MASK) == OBSTRUCT_E)) { dist = sdist - LefGetRouteKeepout(ds->layer); if ((dx - ds->x2 + dist) < xdist) { dir = STUBROUTE_EW | OFFSET_TAP; if ((ds->layer < Num_layers - 1) && (gridx > 0) && (Obs[ds->layer + 1][OGRID( gridx - 1, gridy, ds->layer + 1)] & OBSTRUCT_MASK)) block_route(gridx, gridy, ds->layer, UP); } } else if ((dx <= ds->x1) && ((k & OBSTRUCT_MASK) == OBSTRUCT_W)) { dist = LefGetRouteKeepout(ds->layer) - sdist; if ((ds->x1 - dx - dist) < xdist) { dir = STUBROUTE_EW | OFFSET_TAP; if ((ds->layer < Num_layers - 1) && gridx < (NumChannelsX[ds->layer] - 1) && (Obs[ds->layer + 1][OGRID( gridx + 1, gridy, ds->layer + 1)] & OBSTRUCT_MASK)) block_route(gridx, gridy, ds->layer, UP); } } } if (dx >= (ds->x1 - xdist) && dx <= (ds->x2 + xdist)) { if ((dy >= ds->y2) && ((k & OBSTRUCT_MASK) == OBSTRUCT_N)) { dist = sdist - LefGetRouteKeepout(ds->layer); if ((dy - ds->y2 + dist) < xdist) { dir = STUBROUTE_NS | OFFSET_TAP; if ((ds->layer < Num_layers - 1) && gridy < (NumChannelsY[ds->layer] - 1) && (Obs[ds->layer + 1][OGRID( gridx, gridy - 1, ds->layer + 1)] & OBSTRUCT_MASK)) block_route(gridx, gridy, ds->layer, UP); } } else if ((dy <= ds->y1) && ((k & OBSTRUCT_MASK) == OBSTRUCT_S)) { dist = LefGetRouteKeepout(ds->layer) - sdist; if ((ds->y1 - dy - dist) < xdist) { dir = STUBROUTE_NS | OFFSET_TAP; if ((ds->layer < Num_layers - 1) && (gridy > 0) && (Obs[ds->layer + 1][OGRID( gridx, gridy + 1, ds->layer + 1)] & OBSTRUCT_MASK)) block_route(gridx, gridy, ds->layer, UP); } } } // Otherwise, dir is left as STUBROUTE_X } else { // Cleanly unobstructed area. Define stub // route from point to tap, with a route width // overlap if necessary to avoid a DRC width // violation. if ((dx >= ds->x2) && ((dx - ds->x2) > (dy - ds->y2)) && ((dx - ds->x2) > (ds->y1 - dy))) { // West-pointing stub if ((dy - ds->y2) <= xdist && (ds->y1 - dy) <= xdist) { // Within reach of tap rectangle dir = STUBROUTE_EW; dist = ds->x2 - dx; if (dy < (ds->y2 - xdist) && dy > (ds->y1 + xdist)) { if (dx < ds->x2 + xdist) dist = 0.0; } else { dist -= 2.0 * xdist; } } } else if ((dx <= ds->x1) && ((ds->x1 - dx) > (dy - ds->y2)) && ((ds->x1 - dx) > (ds->y1 - dy))) { // East-pointing stub if ((dy - ds->y2) <= xdist && (ds->y1 - dy) <= xdist) { // Within reach of tap rectangle dir = STUBROUTE_EW; dist = ds->x1 - dx; if (dy < (ds->y2 - xdist) && dy > (ds->y1 + xdist)) { if (dx > ds->x1 - xdist) dist = 0.0; } else { dist += 2.0 * xdist; } } } else if ((dy >= ds->y2) && ((dy - ds->y2) > (dx - ds->x2)) && ((dy - ds->y2) > (ds->x1 - dx))) { // South-pointing stub if ((dx - ds->x2) <= xdist && (ds->x1 - dx) <= xdist) { // Within reach of tap rectangle dir = STUBROUTE_NS; dist = ds->y2 - dy; if (dx < (ds->x2 - xdist) && dx > (ds->x1 + xdist)) { if (dy < ds->y2 + xdist) dist = 0.0; } else { dist -= 2.0 * xdist; } } } else if ((dy <= ds->y1) && ((ds->y1 - dy) > (dx - ds->x2)) && ((ds->y1 - dy) > (ds->x1 - dx))) { // North-pointing stub if ((dx - ds->x2) <= xdist && (ds->x1 - dx) <= xdist) { // Within reach of tap rectangle dir = STUBROUTE_NS; dist = ds->y1 - dy; if (dx < (ds->x2 - xdist) && dx > (ds->x1 + xdist)) { if (dy > ds->y1 - xdist) dist = 0.0; } else { dist += 2.0 * xdist; } } } if (dir == STUBROUTE_X) { // Outside of pin at a corner. First, if one // direction is too far away to connect to a // pin, then we must route the other direction. if (dx < ds->x1 - xdist || dx > ds->x2 + xdist) { if (dy >= ds->y1 - xdist && dy <= ds->y2 + xdist) { dir = STUBROUTE_EW; dist = (float)(((ds->x1 + ds->x2) / 2.0) - dx); } } else if (dy < ds->y1 - xdist || dy > ds->y2 + xdist) { dir = STUBROUTE_NS; dist = (float)(((ds->y1 + ds->y2) / 2.0) - dy); } // Otherwise we are too far away at a diagonal // to reach the pin by moving in any single // direction. To be pedantic, we could define // some jogged stub, but for now, we just call // the point unroutable (leave dir = STUBROUTE_X) } } // Stub distances of <= 1/2 route width are // unnecessary, so don't create them. if (dir == STUBROUTE_NS || dir == STUBROUTE_EW) if (fabs(dist) < (xdist + EPS)) { dir = 0; dist = 0.0; } if ((k < Numnets) && (dir != STUBROUTE_X)) { Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] = (Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] & BLOCKED_MASK) | (u_int)g->netnum[i] | dir; Nodeloc[ds->layer][OGRID(gridx, gridy, ds->layer)] = node; Nodesav[ds->layer][OGRID(gridx, gridy, ds->layer)] = node; } else if ((Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] & NO_NET) != 0) { // Keep showing an obstruction, but add the // direction info and log the stub distance. Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] |= dir; } else { Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] |= (dir | (g->netnum[i] & ROUTED_NET_MASK)); } Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = dist; } else if (epass == 0) { // Position fails euclidean distance check int othernet = (k & ROUTED_NET_MASK); if (othernet != 0 && othernet != (u_int)node->netnum) { // This location is too close to two different // node terminals and should not be used // If there is a stub, then we can't specify // an offset tap, so just disable it. If // there is already an offset, then just // disable it. Otherwise, check if othernet // could be routed using a tap offset. // To avoid having to check all nearby // geometry, place a restriction that the // next grid point in the direction of the // offset must be free (not a tap point of // any net, including this one). That is // still "more restrictive than necessary", // but since the alternative is an efficient // area search for interacting geometry, this // restriction will stand until an example // comes along that requires the detailed // search. if ((k & (STUBROUTE_X | OFFSET_TAP)) != 0) disable_gridpos(gridx, gridy, ds->layer); else if (Nodesav[ds->layer][OGRID(gridx, gridy, ds->layer)] != NULL) { u_char no_offsets = TRUE; int offset_net; // By how much would a tap need to be moved // to clear the obstructing geometry? // Check tap to right if ((dx > ds->x2) && (gridx < NumChannelsX[ds->layer] - 1)) { offset_net = Obs[ds->layer][OGRID(gridx + 1, gridy, ds->layer)]; if (offset_net == 0 || offset_net == othernet) { xdist = 0.5 * LefGetViaWidth(ds->layer, ds->layer, 0); dist = ds->x2 - dx + xdist + LefGetRouteSpacing(ds->layer); dir = (STUBROUTE_EW | OFFSET_TAP); Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = dist; Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] |= dir; no_offsets = FALSE; if ((ds->layer < Num_layers - 1) && (gridx > 0) && (Obs[ds->layer + 1][OGRID( gridx - 1, gridy, ds->layer + 1)] & OBSTRUCT_MASK)) block_route(gridx, gridy, ds->layer, UP); } } // Check tap to left if ((dx < ds->x1) && (gridx > 0)) { offset_net = Obs[ds->layer][OGRID(gridx - 1, gridy, ds->layer)]; if (offset_net == 0 || offset_net == othernet) { xdist = 0.5 * LefGetViaWidth(ds->layer, ds->layer, 0); dist = ds->x1 - dx - xdist - LefGetRouteSpacing(ds->layer); dir = (STUBROUTE_EW | OFFSET_TAP); Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = dist; Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] |= dir; no_offsets = FALSE; if ((ds->layer < Num_layers - 1) && gridx < (NumChannelsX[ds->layer] - 1) && (Obs[ds->layer + 1][OGRID( gridx + 1, gridy, ds->layer + 1)] & OBSTRUCT_MASK)) block_route(gridx, gridy, ds->layer, UP); } } // Check tap up if ((dy > ds->y2) && (gridy < NumChannelsY[ds->layer] - 1)) { offset_net = Obs[ds->layer][OGRID(gridx, gridy + 1, ds->layer)]; if (offset_net == 0 || offset_net == othernet) { xdist = 0.5 * LefGetViaWidth(ds->layer, ds->layer, 1); dist = ds->y2 - dy + xdist + LefGetRouteSpacing(ds->layer); dir = (STUBROUTE_NS | OFFSET_TAP); Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = dist; Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] |= dir; no_offsets = FALSE; if ((ds->layer < Num_layers - 1) && (gridy > 0) && (Obs[ds->layer + 1][OGRID( gridx, gridy + 1, ds->layer + 1)] & OBSTRUCT_MASK)) block_route(gridx, gridy, ds->layer, UP); } } // Check tap down if ((dy < ds->y1) && (gridy > 0)) { offset_net = Obs[ds->layer][OGRID(gridx, gridy - 1, ds->layer)]; if (offset_net == 0 || offset_net == othernet) { xdist = 0.5 * LefGetViaWidth(ds->layer, ds->layer, 1); dist = ds->y1 - dy - xdist - LefGetRouteSpacing(ds->layer); dir = (STUBROUTE_NS | OFFSET_TAP); Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = dist; Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] |= dir; no_offsets = FALSE; if ((ds->layer < Num_layers - 1) && gridx < (NumChannelsX[ds->layer] - 1) && (Obs[ds->layer + 1][OGRID( gridx, gridy - 1, ds->layer + 1)] & OBSTRUCT_MASK)) block_route(gridx, gridy, ds->layer, UP); } } // No offsets were possible, so disable the // position if (no_offsets == TRUE) disable_gridpos(gridx, gridy, ds->layer); } else disable_gridpos(gridx, gridy, ds->layer); } /* If we are on a layer > 0, then this geometry */ /* may block or partially block a pin on layer */ /* zero. Mark this point as belonging to the */ /* net with a stub route to it. */ /* NOTE: This is possibly too restrictive. */ /* May want to force a tap offset for vias on */ /* layer zero. . . */ if ((ds->layer > 0) && (n2 != NULL) && (n2->netnum != node->netnum) && ((othernet == 0) || (othernet == (u_int)node->netnum))) { xdist = 0.5 * LefGetViaWidth(ds->layer, ds->layer, 0); if ((dy + xdist + LefGetRouteSpacing(ds->layer) > ds->y1) && (dy + xdist < ds->y1)) { if ((dx - xdist < ds->x2) && (dx + xdist > ds->x1) && (Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] == 0.0)) { Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = ds->y1 - dy; Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] = (Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] & BLOCKED_MASK) | node->netnum | STUBROUTE_NS; Nodeloc[ds->layer][OGRID(gridx, gridy, ds->layer)] = node; Nodesav[ds->layer][OGRID(gridx, gridy, ds->layer)] = node; } } if ((dy - xdist - LefGetRouteSpacing(ds->layer) < ds->y2) && (dy - xdist > ds->y2)) { if ((dx - xdist < ds->x2) && (dx + xdist > ds->x1) && (Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] == 0.0)) { Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = ds->y2 - dy; Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] = (Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] & BLOCKED_MASK) | node->netnum | STUBROUTE_NS; Nodeloc[ds->layer][OGRID(gridx, gridy, ds->layer)] = node; Nodesav[ds->layer][OGRID(gridx, gridy, ds->layer)] = node; } } xdist = 0.5 * LefGetViaWidth(ds->layer, ds->layer, 1); if ((dx + xdist + LefGetRouteSpacing(ds->layer) > ds->x1) && (dx + xdist < ds->x1)) { if ((dy - xdist < ds->y2) && (dy + xdist > ds->y1) && (Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] == 0.0)) { Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = ds->x1 - dx; Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] = (Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] & BLOCKED_MASK) | node->netnum | STUBROUTE_EW; Nodeloc[ds->layer][OGRID(gridx, gridy, ds->layer)] = node; Nodesav[ds->layer][OGRID(gridx, gridy, ds->layer)] = node; } } if ((dx - xdist - LefGetRouteSpacing(ds->layer) < ds->x2) && (dx - xdist > ds->x2)) { if ((dy - xdist < ds->y2) && (dy + xdist > ds->y1) && (Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] == 0.0)) { Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = ds->x2 - dx; Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] = (Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] & BLOCKED_MASK) | node->netnum | STUBROUTE_EW; Nodeloc[ds->layer][OGRID(gridx, gridy, ds->layer)] = node; Nodesav[ds->layer][OGRID(gridx, gridy, ds->layer)] = node; } } } } } gridy++; } } gridx++; } } } } } } /* void create_obstructions_outside_nodes( void ) */ /*--------------------------------------------------------------*/ /* tap_to_tap_interactions() */ /* */ /* Similar to create_obstructions_from_nodes(), but looks at */ /* each node's tap geometry, looks at every grid point in a */ /* wider area surrounding the tap. If any other node has an */ /* offset that would place it too close to this node's tap */ /* geometry, then we mark the other node as unroutable at that */ /* grid point. */ /*--------------------------------------------------------------*/ void tap_to_tap_interactions() { NODE node; GATE g; DSEG ds; struct dseg_ de; int mingridx, mingridy, maxgridx, maxgridy; int i, gridx, gridy, net, orignet, offset; double dx, dy; float dist; u_char errbox; double deltax[MAX_LAYERS]; double deltay[MAX_LAYERS]; for (i = 0; i < Num_layers; i++) { deltax[i] = 0.5 * LefGetViaWidth(i, i, 0) + LefGetRouteSpacing(i); deltay[i] = 0.5 * LefGetViaWidth(i, i, 1) + LefGetRouteSpacing(i); } for (g = Nlgates; g; g = g->next) { for (i = 0; i < g->nodes; i++) { net = g->netnum[i]; if (net != 0) { // Get the node record associated with this pin. node = g->noderec[i]; for (ds = g->taps[i]; ds; ds = ds->next) { mingridx = (int)((ds->x1 - Xlowerbound) / PitchX[ds->layer]) - 1; if (mingridx < 0) mingridx = 0; maxgridx = (int)((ds->x2 - Xlowerbound) / PitchX[ds->layer]) + 2; if (maxgridx >= NumChannelsX[ds->layer]) maxgridx = NumChannelsX[ds->layer] - 1; mingridy = (int)((ds->y1 - Ylowerbound) / PitchY[ds->layer]) - 1; if (mingridy < 0) mingridy = 0; maxgridy = (int)((ds->y2 - Ylowerbound) / PitchY[ds->layer]) + 2; if (maxgridy >= NumChannelsY[ds->layer]) maxgridy = NumChannelsY[ds->layer] - 1; for (gridx = mingridx; gridx <= maxgridx; gridx++) { for (gridy = mingridy; gridy <= maxgridy; gridy++) { /* Is there an offset tap at this position, and */ /* does it belong to a net that is != net? */ orignet = Obs[ds->layer][OGRID(gridx, gridy, ds->layer)]; if (orignet & OFFSET_TAP) { offset = orignet & PINOBSTRUCTMASK; orignet &= ROUTED_NET_MASK; if (orignet != net) { dx = (gridx * PitchX[ds->layer]) + Xlowerbound; dy = (gridy * PitchY[ds->layer]) + Ylowerbound; dist = Stub[ds->layer][OGRID(gridx, gridy, ds->layer)]; /* "de" is the bounding box of a via placed */ /* at (gridx, gridy) and offset as specified. */ /* Expanded by metal spacing requirement. */ de.x1 = dx - deltax[ds->layer]; de.x2 = dx + deltax[ds->layer]; de.y1 = dy - deltay[ds->layer]; de.y2 = dy + deltay[ds->layer]; if (offset == (STUBROUTE_NS | OFFSET_TAP)) { de.y1 += dist; de.y2 += dist; } else if (offset == (STUBROUTE_EW | OFFSET_TAP)) { de.x1 += dist; de.x2 += dist; } // Shrink by EPS to avoid roundoff errors de.x1 += EPS; de.x2 -= EPS; de.y1 += EPS; de.y2 -= EPS; /* Does the via bounding box interact with */ /* the tap geometry? */ if ((de.x1 < ds->x2) && (ds->x1 < de.x2) && (de.y1 < ds->y2) && (ds->y1 < de.y2)) disable_gridpos(gridx, gridy, ds->layer); } } } } } } } } } /*--------------------------------------------------------------*/ /* make_routable() */ /* */ /* In the case that a node can't be routed because it has no */ /* available tap points, but there is tap geometry recorded */ /* for the node, then take the first available grid location */ /* near the tap. This, of course, bypasses all of qrouter's */ /* DRC checks. But it is only meant to be a stop-gap measure */ /* to get qrouter to complete all routes, and may work in */ /* cases where, say, the tap passes euclidean rules but not */ /* manhattan rules. */ /*--------------------------------------------------------------*/ void make_routable(NODE node) { GATE g; DSEG ds; int i, gridx, gridy, net; double dx, dy; /* The database is not organized to find tap points */ /* from nodes, so we have to search for the node. */ /* Fortunately this routine isn't normally called. */ for (g = Nlgates; g; g = g->next) { for (i = 0; i < g->nodes; i++) { if (g->noderec[i] == node) { for (ds = g->taps[i]; ds; ds = ds->next) { gridx = (int)((ds->x1 - Xlowerbound) / PitchX[ds->layer]) - 1; while (1) { dx = (gridx * PitchX[ds->layer]) + Xlowerbound; if (dx > ds->x2 || gridx >= NumChannelsX[ds->layer]) break; else if (dx >= ds->x1 && gridx >= 0) { gridy = (int)((ds->y1 - Ylowerbound) / PitchY[ds->layer]) - 1; while (1) { dy = (gridy * PitchY[ds->layer]) + Ylowerbound; if (dy > ds->y2 || gridy >= NumChannelsY[ds->layer]) break; // Area inside defined pin geometry if (dy > ds->y1 && gridy >= 0) { int orignet = Obs[ds->layer][OGRID(gridx, gridy, ds->layer)]; if (orignet & NO_NET) { Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] = g->netnum[i]; Nodeloc[ds->layer][OGRID(gridx, gridy, ds->layer)] = node; Nodesav[ds->layer][OGRID(gridx, gridy, ds->layer)] = node; return; } } gridy++; } } gridx++; } } } } } } /*--------------------------------------------------------------*/ /* adjust_stub_lengths() */ /* */ /* Makes an additional pass through the tap and obstruction */ /* databases, checking geometry against the potential stub */ /* routes for DRC spacing violations. Adjust stub routes as */ /* necessary to resolve the DRC error(s). */ /* */ /* ARGS: none. */ /* RETURNS: nothing */ /* SIDE EFFECTS: none */ /* AUTHOR: Tim Edwards, April 2013 */ /*--------------------------------------------------------------*/ void adjust_stub_lengths() { NODE node, n2; GATE g; DPOINT dp; DSEG ds, ds2; struct dseg_ dt, de; u_int dir, k; int i, gx, gy, gridx, gridy, net, orignet; double dx, dy, wx, wy, s, dd; float dist; u_char errbox; // For each node terminal (gate pin), look at the surrounding grid points. // If any define a stub route or an offset, check if the stub geometry // or offset geometry would create a DRC spacing violation. If so, adjust // the stub route to resolve the error. If the error cannot be resolved, // mark the position as unroutable. If it is the ONLY grid point accessible // to the pin, keep it as-is and flag a warning. // Unlike blockage-finding routines, which look in an area of a size equal // to the DRC interaction distance around a tap rectangle, this routine looks // out one grid pitch in each direction, to catch information about stubs that // may terminate within a DRC interaction distance of the tap rectangle. for (g = Nlgates; g; g = g->next) { for (i = 0; i < g->nodes; i++) { if (g->netnum[i] != 0) { // Get the node record associated with this pin. node = g->noderec[i]; if (node == NULL) continue; // Work through each rectangle in the tap geometry for (ds = g->taps[i]; ds; ds = ds->next) { wx = 0.5 * LefGetViaWidth(ds->layer, ds->layer, 0); wy = 0.5 * LefGetViaWidth(ds->layer, ds->layer, 1); s = LefGetRouteSpacing(ds->layer); gridx = (int)((ds->x1 - Xlowerbound - PitchX[ds->layer]) / PitchX[ds->layer]) - 1; while (1) { dx = (gridx * PitchX[ds->layer]) + Xlowerbound; if (dx > (ds->x2 + PitchX[ds->layer]) || gridx >= NumChannelsX[ds->layer]) break; else if (dx >= (ds->x1 - PitchX[ds->layer]) && gridx >= 0) { gridy = (int)((ds->y1 - Ylowerbound - PitchY[ds->layer]) / PitchY[ds->layer]) - 1; while (1) { dy = (gridy * PitchY[ds->layer]) + Ylowerbound; if (dy > (ds->y2 + PitchY[ds->layer]) || gridy >= NumChannelsY[ds->layer]) break; if (dy >= (ds->y1 - PitchY[ds->layer]) && gridy >= 0) { orignet = Obs[ds->layer][OGRID(gridx, gridy, ds->layer)]; // Ignore this location if it is assigned to another // net, or is assigned to NO_NET. if ((orignet & ROUTED_NET_MASK) != node->netnum) { gridy++; continue; } // STUBROUTE_X are unroutable; leave them alone if ((orignet & PINOBSTRUCTMASK) == STUBROUTE_X) { gridy++; continue; } // define a route box around the grid point errbox = FALSE; dt.x1 = dx - wx; dt.x2 = dx + wx; dt.y1 = dy - wy; dt.y2 = dy + wy; dist = Stub[ds->layer][OGRID(gridx, gridy, ds->layer)]; // adjust the route box according to the stub // or offset geometry, provided that the stub // is longer than the route box. if (orignet & OFFSET_TAP) { if (orignet & STUBROUTE_EW) { dt.x1 += dist; dt.x2 += dist; } else if (orignet & STUBROUTE_NS) { dt.y1 += dist; dt.y2 += dist; } } else if (orignet & PINOBSTRUCTMASK) { if (orignet & STUBROUTE_EW) { if (dist > EPS) { if (dx + dist > dt.x2) dt.x2 = dx + dist; } else { if (dx + dist < dt.x1) dt.x1 = dx + dist; } } else if (orignet & STUBROUTE_NS) { if (dist > EPS) { if (dy + dist > dt.y2) dt.y2 = dy + dist; } else { if (dy + dist < dt.y1) dt.y1 = dy + dist; } } } de = dt; // check for DRC spacing interactions between // the tap box and the route box if ((dt.y1 - ds->y2) > EPS && (dt.y1 - ds->y2) < s) { if (ds->x2 > (dt.x1 - s) && ds->x1 < (dt.x2 + s)) { de.y2 = dt.y1; de.y1 = ds->y2; if (ds->x2 + s < dt.x2) de.x2 = ds->x2 + s; if (ds->x1 - s > dt.x1) de.x1 = ds->x1 - s; errbox = TRUE; } } else if ((ds->y1 - dt.y2) > EPS && (ds->y1 - dt.y2) < s) { if (ds->x2 > (dt.x1 - s) && ds->x1 < (dt.x2 + s)) { de.y1 = dt.y2; de.y2 = ds->y1; if (ds->x2 + s < dt.x2) de.x2 = ds->x2 + s; if (ds->x1 - s > dt.x1) de.x1 = ds->x1 - s; errbox = TRUE; } } if ((dt.x1 - ds->x2) > EPS && (dt.x1 - ds->x2) < s) { if (ds->y2 > (dt.y1 - s) && ds->y1 < (dt.y2 + s)) { de.x2 = dt.x1; de.x1 = ds->x2; if (ds->y2 + s < dt.y2) de.y2 = ds->y2 + s; if (ds->y1 - s > dt.y1) de.y1 = ds->y1 - s; errbox = TRUE; } } else if ((ds->x1 - dt.x2) > EPS && (ds->x1 - dt.x2) < s) { if (ds->y2 > (dt.y1 - s) && ds->y1 < (dt.y2 + s)) { de.x1 = dt.x2; de.x2 = ds->x1; if (ds->y2 + s < dt.y2) de.y2 = ds->y2 + s; if (ds->y1 - s > dt.y1) de.y1 = ds->y1 - s; errbox = TRUE; } } if (errbox == TRUE) { // Chop areas off the error box that are covered by // other taps of the same port. for (ds2 = g->taps[i]; ds2; ds2 = ds2->next) { if (ds2 == ds) continue; if (ds2->layer != ds->layer) continue; if (ds2->x1 <= de.x1 && ds2->x2 >= de.x2 && ds2->y1 <= de.y1 && ds2->y2 >= de.y2) { errbox = FALSE; // Completely covered break; } // Look for partial coverage. Note that any // change can cause a change in the original // two conditionals, so we have to keep // evaluating those conditionals. if (ds2->x1 < de.x2 && ds2->x2 > de.x1) if (ds2->y1 < de.y2 && ds2->y2 > de.y1) // if (ds2->x1 < de.x1 - EPS && if (ds2->x1 < de.x1 + EPS && ds2->x2 < de.x2 - EPS) { de.x1 = ds2->x2; if (ds2->x2 >= ds->x2) errbox = FALSE; } if (ds2->x1 < de.x2 && ds2->x2 > de.x1) if (ds2->y1 < de.y2 && ds2->y2 > de.y1) // if (ds2->x2 > de.x2 + EPS && if (ds2->x2 > de.x2 - EPS && ds2->x1 > de.x1 + EPS) { de.x2 = ds2->x1; if (ds2->x1 <= ds->x1) errbox = FALSE; } if (ds2->x1 < de.x2 && ds2->x2 > de.x1) if (ds2->y1 < de.y2 && ds2->y2 > de.y1) // if (ds2->y1 < de.y1 - EPS && if (ds2->y1 < de.y1 + EPS && ds2->y2 < de.y2 - EPS) { de.y1 = ds2->y2; if (ds2->y2 >= ds->y2) errbox = FALSE; } if (ds2->x1 < de.x2 && ds2->x2 > de.x1) if (ds2->y1 < de.y2 && ds2->y2 > de.y1) // if (ds2->y2 > de.y2 + EPS && if (ds2->y2 > de.y2 - EPS && ds2->y1 > de.y1 + EPS) { de.y2 = ds2->y1; if (ds2->y1 <= ds->y1) errbox = FALSE; } } } // Any area left over is a potential DRC error. if ((de.x2 <= de.x1) || (de.y2 <= de.y1)) errbox = FALSE; if (errbox == TRUE) { // Create stub route to cover error box, or // if possible, stretch existing stub route // to cover error box. // Allow EW stubs to be changed to NS stubs and // vice versa if the original stub length was less // than a route width. This means the grid position // makes contact without the stub. Moving the stub // to another side should not create an error. // NOTE: Changed 4/29/13; direction of stub will // be changed even though it might create an error // in the other direction; it can't do worse. // But, the case should be re-run to check (to-do) // NOTE 2: Changed again 1/8/14; error box must // touch ds geometry. // Changed again 2/5/14: error box must touch // ds geometry by more than just a point. <= // changed to < and >= changed to > /* if (de.x2 > dt.x2) { */ if ((de.x2 > dt.x2) && (de.y1 < ds->y2) && (de.y2 > ds->y1)) { if ((orignet & PINOBSTRUCTMASK) == 0) { Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] |= STUBROUTE_EW; Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = de.x2 - dx; errbox = FALSE; } else if ((orignet & PINOBSTRUCTMASK) == STUBROUTE_EW && (dist > 0)) { Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = de.x2 - dx; errbox = FALSE; } else if ((orignet & PINOBSTRUCTMASK) == STUBROUTE_NS) { Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] &= ~STUBROUTE_NS; Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] |= STUBROUTE_EW; Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = de.x2 - dx; errbox = FALSE; } } /* else if (de.x1 < dt.x1) { */ else if ((de.x1 < dt.x1) && (de.y1 < ds->y2) && (de.y2 > ds->y1)) { if ((orignet & PINOBSTRUCTMASK) == 0) { Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] |= STUBROUTE_EW; Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = de.x1 - dx; errbox = FALSE; } else if ((orignet & PINOBSTRUCTMASK) == STUBROUTE_EW && (dist < 0)) { Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = de.x1 - dx; errbox = FALSE; } else if ((orignet & PINOBSTRUCTMASK) == STUBROUTE_NS) { Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] &= ~STUBROUTE_NS; Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] |= STUBROUTE_EW; Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = de.x1 - dx; errbox = FALSE; } } /* else if (de.y2 > dt.y2) { */ else if ((de.y2 > dt.y2) && (de.x1 < ds->x2) && (de.x2 > ds->x1)) { if ((orignet & PINOBSTRUCTMASK) == 0) { Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] |= STUBROUTE_NS; Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = de.y2 - dy; errbox = FALSE; } else if ((orignet & PINOBSTRUCTMASK) == STUBROUTE_NS && (dist > 0)) { Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = de.y2 - dy; errbox = FALSE; } else if ((orignet & PINOBSTRUCTMASK) == STUBROUTE_EW) { Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] &= ~STUBROUTE_EW; Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] |= STUBROUTE_NS; Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = de.y2 - dy; errbox = FALSE; } } /* else if (de.y1 < dt.y1) { */ else if ((de.y1 < dt.y1) && (de.x1 < ds->x2) && (de.x2 > ds->x1)) { if ((orignet & PINOBSTRUCTMASK) == 0) { Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] |= STUBROUTE_NS; Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = de.y1 - dy; errbox = FALSE; } else if ((orignet & PINOBSTRUCTMASK) == STUBROUTE_NS && (dist < 0)) { Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = de.y1 - dy; errbox = FALSE; } else if ((orignet & PINOBSTRUCTMASK) == STUBROUTE_EW) { Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] &= ~STUBROUTE_EW; Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] |= STUBROUTE_NS; Stub[ds->layer][OGRID(gridx, gridy, ds->layer)] = de.y1 - dy; errbox = FALSE; } } // Where the error box did not touch the stub // route, there is assumed to be no error. if (errbox == TRUE) if ((de.x2 > dt.x2) || (de.x1 < dt.x1) || (de.y2 > dt.y2) || (de.y1 < dt.y1)) errbox = FALSE; if (errbox == TRUE) { // Unroutable position, so mark it unroutable Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] |= STUBROUTE_X; } } } gridy++; } } gridx++; } } } } } } /* void adjust_stub_lengths() */ /*--------------------------------------------------------------*/ /* block_route() */ /* */ /* Mark a specific length along the route tracks as unroutable */ /* by finding the grid point in the direction indicated, and */ /* setting the appropriate block bit in the Obs[] array for */ /* that position. The original grid point is marked as */ /* unroutable in the opposite direction, for symmetry. */ /*--------------------------------------------------------------*/ void block_route(int x, int y, int lay, u_char dir) { int bx, by, bl, ob; bx = x; by = y; bl = lay; switch (dir) { case NORTH: if (y == NumChannelsY[lay] - 1) return; by = y + 1; break; case SOUTH: if (y == 0) return; by = y - 1; break; case EAST: if (x == NumChannelsX[lay] - 1) return; bx = x + 1; break; case WEST: if (x == 0) return; bx = x - 1; break; case UP: if (lay == Num_layers - 1) return; bl = lay + 1; break; case DOWN: if (lay == 0) return; bl = lay - 1; break; } ob = Obs[bl][OGRID(bx, by, bl)]; if ((ob & NO_NET) != 0) return; switch (dir) { case NORTH: Obs[bl][OGRID(bx, by, bl)] |= BLOCKED_S; Obs[lay][OGRID(x, y, lay)] |= BLOCKED_N; break; case SOUTH: Obs[bl][OGRID(bx, by, bl)] |= BLOCKED_N; Obs[lay][OGRID(x, y, lay)] |= BLOCKED_S; break; case EAST: Obs[bl][OGRID(bx, by, bl)] |= BLOCKED_W; Obs[lay][OGRID(x, y, lay)] |= BLOCKED_E; break; case WEST: Obs[bl][OGRID(bx, by, bl)] |= BLOCKED_E; Obs[lay][OGRID(x, y, lay)] |= BLOCKED_W; break; case UP: Obs[bl][OGRID(bx, by, bl)] |= BLOCKED_D; Obs[lay][OGRID(x, y, lay)] |= BLOCKED_U; break; case DOWN: Obs[bl][OGRID(bx, by, bl)] |= BLOCKED_U; Obs[lay][OGRID(x, y, lay)] |= BLOCKED_D; break; } } /*--------------------------------------------------------------*/ /* find_route_blocks() --- */ /* */ /* Search tap geometry for edges that cause DRC spacing */ /* errors with route edges. This specifically checks */ /* edges of the route tracks, not the intersection points. */ /* If a tap would cause an error with a route segment, */ /* the grid points on either end of the segment are */ /* flagged to prevent generating a route along that */ /* specific segment. */ /*--------------------------------------------------------------*/ void find_route_blocks() { NODE node; GATE g; // DPOINT dp; DSEG ds, ds2; struct dseg_ dt, de; int i, gridx, gridy; double dx, dy, w, v, s, u; float dist; u_char errbox; for (g = Nlgates; g; g = g->next) { for (i = 0; i < g->nodes; i++) { if (g->netnum[i] != 0) { // Get the node record associated with this pin. node = g->noderec[i]; // Work through each rectangle in the tap geometry for (ds = g->taps[i]; ds; ds = ds->next) { w = 0.5 * LefGetRouteWidth(ds->layer); v = 0.5 * LefGetViaWidth(ds->layer, ds->layer, 0); s = LefGetRouteSpacing(ds->layer); // Look west gridx = (int)((ds->x1 - Xlowerbound) / PitchX[ds->layer]); dx = (gridx * PitchX[ds->layer]) + Xlowerbound; dist = ds->x1 - dx - w; if (dist > 0 && dist < s && gridx >= 0) { dt.x1 = dt.x2 = dx; dt.y1 = ds->y1; dt.y2 = ds->y2; // Check for other taps covering this edge // (to do) // Find all grid points affected gridy = (int)((ds->y1 - Ylowerbound - PitchY[ds->layer]) / PitchY[ds->layer]); dy = (gridy * PitchY[ds->layer]) + Ylowerbound; while (dy < ds->y1 - s) { dy += PitchY[ds->layer]; gridy++; } while (dy < ds->y2 + s) { u = ((Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] & PINOBSTRUCTMASK) == STUBROUTE_EW) ? v : w; if (dy + EPS < ds->y2 - u) block_route(gridx, gridy, ds->layer, NORTH); if (dy - EPS > ds->y1 + u) block_route(gridx, gridy, ds->layer, SOUTH); dy += PitchY[ds->layer]; gridy++; } } // Look east gridx = (int)(1.0 + (ds->x2 - Xlowerbound) / PitchX[ds->layer]); dx = (gridx * PitchX[ds->layer]) + Xlowerbound; dist = dx - ds->x2 - w; if (dist > 0 && dist < s && gridx < NumChannelsX[ds->layer]) { dt.x1 = dt.x2 = dx; dt.y1 = ds->y1; dt.y2 = ds->y2; // Check for other taps covering this edge // (to do) // Find all grid points affected gridy = (int)((ds->y1 - Ylowerbound - PitchY[ds->layer]) / PitchY[ds->layer]); dy = (gridy * PitchY[ds->layer]) + Ylowerbound; while (dy < ds->y1 - s) { dy += PitchY[ds->layer]; gridy++; } while (dy < ds->y2 + s) { u = ((Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] & PINOBSTRUCTMASK) == STUBROUTE_EW) ? v : w; if (dy + EPS < ds->y2 - u) block_route(gridx, gridy, ds->layer, NORTH); if (dy - EPS > ds->y1 + u) block_route(gridx, gridy, ds->layer, SOUTH); dy += PitchY[ds->layer]; gridy++; } } // Look south gridy = (int)((ds->y1 - Ylowerbound) / PitchY[ds->layer]); dy = (gridy * PitchY[ds->layer]) + Ylowerbound; dist = ds->y1 - dy - w; if (dist > 0 && dist < s && gridy >= 0) { dt.x1 = ds->x1; dt.x2 = ds->x2; dt.y1 = dt.y2 = dy; // Check for other taps covering this edge // (to do) // Find all grid points affected gridx = (int)((ds->x1 - Xlowerbound - PitchX[ds->layer]) / PitchX[ds->layer]); dx = (gridx * PitchX[ds->layer]) + Xlowerbound; while (dx < ds->x1 - s) { dx += PitchX[ds->layer]; gridx++; } while (dx < ds->x2 + s) { u = ((Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] & PINOBSTRUCTMASK) == STUBROUTE_NS) ? v : w; if (dx + EPS < ds->x2 - u) block_route(gridx, gridy, ds->layer, EAST); if (dx - EPS > ds->x1 + u) block_route(gridx, gridy, ds->layer, WEST); dx += PitchX[ds->layer]; gridx++; } } // Look north gridy = (int)(1.0 + (ds->y2 - Ylowerbound) / PitchY[ds->layer]); dy = (gridy * PitchY[ds->layer]) + Ylowerbound; dist = dy - ds->y2 - w; if (dist > 0 && dist < s && gridy < NumChannelsY[ds->layer]) { dt.x1 = ds->x1; dt.x2 = ds->x2; dt.y1 = dt.y2 = dy; // Check for other taps covering this edge // (to do) // Find all grid points affected gridx = (int)((ds->x1 - Xlowerbound - PitchX[ds->layer]) / PitchX[ds->layer]); dx = (gridx * PitchX[ds->layer]) + Xlowerbound; while (dx < ds->x1 - s) { dx += PitchX[ds->layer]; gridx++; } while (dx < ds->x2 + s) { u = ((Obs[ds->layer][OGRID(gridx, gridy, ds->layer)] & PINOBSTRUCTMASK) == STUBROUTE_NS) ? v : w; if (dx + EPS < ds->x2 - u) block_route(gridx, gridy, ds->layer, EAST); if (dx - EPS > ds->x1 + u) block_route(gridx, gridy, ds->layer, WEST); dx += PitchX[ds->layer]; gridx++; } } } } } } } /* node.c */ qrouter-1.3.33/node.h0000664000175000001440000000166312620407431013117 0ustar timusers/*--------------------------------------------------------------*/ /* node.h -- general purpose autorouter */ /*--------------------------------------------------------------*/ /* Written by Tim Edwards, based on code by Steve Beccue, 2003 */ /*--------------------------------------------------------------*/ #ifndef NODE_H #define GND_NET 1 #define VDD_NET 2 #define MIN_NET_NUMBER 3 void create_netorder(u_char method); void find_bounding_box(NET net); void create_obstructions_inside_nodes(); void create_obstructions_outside_nodes(); void create_obstructions_from_gates(); void create_obstructions_from_variable_pitch(); void tap_to_tap_interactions(); void make_routable(NODE node); void adjust_stub_lengths(); void expand_tap_geometry(); void block_route(int x, int y, int lay, u_char dir); void print_nodes(char *filename); void print_nlnets(char *filename); #define NODE_H #endif /* end of node.h */ qrouter-1.3.33/config.sub0000755000175000001440000006700512406043443014005 0ustar timusers#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 # Free Software Foundation, Inc. timestamp='2001-08-13' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit 0;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | storm-chaos* | os2-emx* | windows32-*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | c4x | clipper \ | d10v | d30v | dsp16xx \ | fr30 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | m32r | m68000 | m68k | m88k | mcore \ | mips16 | mips64 | mips64el | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el | mips64vr4300 \ | mips64vr4300el | mips64vr5000 | mips64vr5000el \ | mipsbe | mipsel | mipsle | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | ns16k | ns32k \ | openrisc \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | s390 | s390x \ | sh | sh[34] | sh[34]eb | shbe | shle \ | sparc | sparc64 | sparclet | sparclite | sparcv9 | sparcv9b \ | strongarm \ | tahoe | thumb | tic80 | tron \ | v850 \ | we32k \ | x86 | xscale \ | z8k) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alphapca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armv*-* \ | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c54x-* \ | clipper-* | cray2-* | cydra-* \ | d10v-* | d30v-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | m32r-* \ | m68000-* | m680[01234]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | mcore-* \ | mips-* | mips16-* | mips64-* | mips64el-* | mips64orion-* \ | mips64orionel-* | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* | mipsbe-* | mipsel-* \ | mipsle-* | mipstx39-* | mipstx39el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | s390-* | s390x-* \ | sh-* | sh[34]-* | sh[34]eb-* | shbe-* | shle-* \ | sparc-* | sparc64-* | sparc86x-* | sparclite-* \ | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* \ | t3e-* | tahoe-* | thumb-* | tic30-* | tic54x-* | tic80-* | tron-* \ | v850-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xmp-* | xps100-* | xscale-* \ | ymp-* \ | z8k-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | ymp) basic_machine=ymp-cray os=-unicos ;; cray2) basic_machine=cray2-cray os=-unicos ;; [cjt]90) basic_machine=${basic_machine}-cray os=-unicos ;; crds | unos) basic_machine=m68k-crds ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mipsel*-linux*) basic_machine=mipsel-unknown os=-linux-gnu ;; mips*-linux*) basic_machine=mips-unknown os=-linux-gnu ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; mmix*) basic_machine=mmix-knuth os=-mmixware ;; monitor) basic_machine=m68k-rom68k os=-coff ;; msdos) basic_machine=i386-pc os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pentium | p5 | k5 | k6 | nexgen) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon) basic_machine=i686-pc ;; pentiumii | pentium2) basic_machine=i686-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sparclite-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=t3e-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; tower | tower-32) basic_machine=m68k-ncr ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; windows32) basic_machine=i386-pc os=-windows32-msvcrt ;; xmp) basic_machine=xmp-cray os=-unicos ;; xps | xps100) basic_machine=xps100-honeywell ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; mips) if [ x$os = x-linux-gnu ]; then basic_machine=mips-unknown else basic_machine=mips-mips fi ;; romp) basic_machine=romp-ibm ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh3 | sh4 | sh3eb | sh4eb) basic_machine=sh-unknown ;; sparc | sparcv9 | sparcv9b) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; c4x*) basic_machine=c4x-none os=-coff ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto*) os=-nto-qnx ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-ibm) os=-aix ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -ptx*) vendor=sequent ;; -vxsim* | -vxworks*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: qrouter-1.3.33/graphics.c0000664000175000001440000004326012607327770014000 0ustar timusers/*------------------------------------------------------*/ /* Graphics routines for qrouter */ /*------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include "qrouter.h" #include "qconfig.h" #include "node.h" #include "maze.h" #include "lef.h" /*------------------------------*/ /* Type declarations */ /*------------------------------*/ void load_font(XFontStruct **); void createGC(Window, GC *, XFontStruct *); /*----------------------------------*/ /* Global variables for X11 drawing */ /*----------------------------------*/ XFontStruct *font_info; Pixmap buffer = (Pixmap)0; Display *dpy; Window win; Colormap cmap; GC gc; Dimension width, height; #define SHORTSPAN 10 #define LONGSPAN 127 int spacing; int bluepix, greenpix, redpix, cyanpix, orangepix, goldpix; int blackpix, whitepix, graypix, ltgraypix, yellowpix; int magentapix, purplepix, greenyellowpix; int brownvector[SHORTSPAN]; int bluevector[LONGSPAN]; /*--------------------------------------------------------------*/ /* Highlight a position on the graph. Do this on the actual */ /* screen, not the buffer. */ /*--------------------------------------------------------------*/ void highlight(int x, int y) { int i, xspc, yspc, hspc; PROUTE *Pr; // If Obs2[] at x, y is a source or dest, don't highlight // Do this only for layer 0; it doesn't have to be rigorous. for (i = 0; i < Num_layers; i++) { Pr = &Obs2[i][OGRID(x, y, i)]; if (Pr->flags & (PR_SOURCE | PR_TARGET)) return; } hspc = spacing >> 1; if (hspc == 0) hspc = 1; xspc = (x + 1) * spacing - hspc; yspc = height - (y + 1) * spacing - hspc; XSetForeground(dpy, gc, yellowpix); XFillRectangle(dpy, win, gc, xspc, yspc, spacing, spacing); XFlush(dpy); } /*--------------------------------------*/ /* Highlight source (in magenta) */ /*--------------------------------------*/ void highlight_source() { int xspc, yspc, hspc; int i, x, y; PROUTE *Pr; if (Obs2[0] == NULL) return; // Determine the number of routes per width and height, if // it has not yet been computed hspc = spacing >> 1; if (hspc == 0) hspc = 1; // Draw source pins as magenta squares XSetForeground(dpy, gc, magentapix); for (i = 0; i < Num_layers; i++) { for (x = 0; x < NumChannelsX[i]; x++) { xspc = (x + 1) * spacing - hspc; for (y = 0; y < NumChannelsY[i]; y++) { Pr = &Obs2[i][OGRID(x, y, i)]; if (Pr->flags & PR_SOURCE) { yspc = height - (y + 1) * spacing - hspc; XFillRectangle(dpy, win, gc, xspc, yspc, spacing, spacing); } } } } XFlush(dpy); } /*--------------------------------------*/ /* Highlight destination (in purple) */ /*--------------------------------------*/ void highlight_dest() { int xspc, yspc, hspc, dspc; int i, x, y; PROUTE *Pr; if (Obs2[0] == NULL) return; // Determine the number of routes per width and height, if // it has not yet been computed dspc = spacing + 4; // Make target more visible hspc = dspc >> 1; // Draw destination pins as purple squares XSetForeground(dpy, gc, purplepix); for (i = 0; i < Num_layers; i++) { for (x = 0; x < NumChannelsX[i]; x++) { xspc = (x + 1) * spacing - hspc; for (y = 0; y < NumChannelsY[i]; y++) { Pr = &Obs2[i][OGRID(x, y, i)]; if (Pr->flags & PR_TARGET) { yspc = height - (y + 1) * spacing - hspc; XFillRectangle(dpy, win, gc, xspc, yspc, dspc, dspc); } } } } XFlush(dpy); } /*----------------------------------------------*/ /* Highlight all the search starting points */ /*----------------------------------------------*/ void highlight_starts(POINT glist) { int xspc, yspc, hspc; POINT gpoint; // Determine the number of routes per width and height, if // it has not yet been computed hspc = spacing >> 1; XSetForeground(dpy, gc, greenyellowpix); for (gpoint = glist; gpoint; gpoint = gpoint->next) { xspc = (gpoint->x1 + 1) * spacing - hspc; yspc = height - (gpoint->y1 + 1) * spacing - hspc; XFillRectangle(dpy, win, gc, xspc, yspc, spacing, spacing); } XFlush(dpy); } /*--------------------------------------*/ /* Highlight mask (in tan) */ /*--------------------------------------*/ void highlight_mask() { int xspc, yspc, hspc; int x, y; u_char value; if (RMask == NULL) return; // Determine the number of routes per width and height, if // it has not yet been computed hspc = spacing >> 1; // Draw destination pins as tan squares for (x = 0; x < NumChannelsX[0]; x++) { xspc = (x + 1) * spacing - hspc; for (y = 0; y < NumChannelsY[0]; y++) { XSetForeground(dpy, gc, brownvector[RMask[OGRID(x, y, 0)]]); yspc = height - (y + 1) * spacing - hspc; XFillRectangle(dpy, win, gc, xspc, yspc, spacing, spacing); } } XFlush(dpy); } /*----------------------------------------------*/ /* Draw a map of obstructions and pins */ /*----------------------------------------------*/ void map_obstruction() { int xspc, yspc, hspc; int i, x, y, n, norm; u_char *Congestion; u_char value, maxval; hspc = spacing >> 1; // Draw obstructions as light gray squares XSetForeground(dpy, gc, ltgraypix); for (i = 0; i < Num_layers; i++) { for (x = 0; x < NumChannelsX[i]; x++) { xspc = (x + 1) * spacing - hspc; for (y = 0; y < NumChannelsY[i]; y++) { if (Obs[i][OGRID(x, y, i)] & NO_NET) { yspc = height - (y + 1) * spacing - hspc; XFillRectangle(dpy, buffer, gc, xspc, yspc, spacing, spacing); } } } } // Draw pins as gray squares XSetForeground(dpy, gc, graypix); for (i = 0; i < Pinlayers; i++) { for (x = 0; x < NumChannelsX[i]; x++) { xspc = (x + 1) * spacing - hspc; for (y = 0; y < NumChannelsY[i]; y++) { if (Nodesav[i][OGRID(x, y, i)] != NULL) { yspc = height - (y + 1) * spacing - hspc; XFillRectangle(dpy, buffer, gc, xspc, yspc, spacing, spacing); } } } } } /*----------------------------------------------*/ /* Draw a map of actual route congestion */ /*----------------------------------------------*/ void map_congestion() { int xspc, yspc, hspc; int i, x, y, n, norm; u_char *Congestion; u_char value, maxval; hspc = spacing >> 1; Congestion = (u_char *)calloc(NumChannelsX[0] * NumChannelsY[0], sizeof(u_char)); // Analyze Obs[] array for congestion for (i = 0; i < Num_layers; i++) { for (x = 0; x < NumChannelsX[i]; x++) { for (y = 0; y < NumChannelsY[i]; y++) { value = (u_char)0; n = Obs[i][OGRID(x, y, i)]; if (n & ROUTED_NET) value++; if (n & BLOCKED_MASK) value++; if (n & NO_NET) value++; if (n & PINOBSTRUCTMASK) value++; Congestion[OGRID(x, y, 0)] += value; } } } maxval = 0; for (x = 0; x < NumChannelsX[0]; x++) { for (y = 0; y < NumChannelsY[0]; y++) { value = Congestion[OGRID(x, y, 0)]; if (value > maxval) maxval = value; } } norm = (LONGSPAN - 1) / maxval; // Draw destination pins as blue squares for (x = 0; x < NumChannelsX[0]; x++) { xspc = (x + 1) * spacing - hspc; for (y = 0; y < NumChannelsY[0]; y++) { XSetForeground(dpy, gc, bluevector[norm * Congestion[OGRID(x, y, 0)]]); yspc = height - (y + 1) * spacing - hspc; XFillRectangle(dpy, buffer, gc, xspc, yspc, spacing, spacing); } } // Cleanup free(Congestion); } /*----------------------------------------------------------------------*/ /* Draw a map of route congestion estimated from net bounding boxes */ /*----------------------------------------------------------------------*/ void map_estimate() { NET net; int xspc, yspc, hspc; int i, x, y, nwidth, nheight, area, length, value; float density, *Congestion, norm, maxval; hspc = spacing >> 1; Congestion = (float *)calloc(NumChannelsX[0] * NumChannelsY[0], sizeof(float)); // Use net bounding boxes to estimate congestion for (i = 0; i < Numnets; i++) { net = Nlnets[i]; nwidth = (net->xmax - net->xmin + 1); nheight = (net->ymax - net->ymin + 1); area = nwidth * nheight; if (nwidth > nheight) { length = nwidth + (nheight >> 1) * net->numnodes; } else { length = nheight + (nwidth >> 1) * net->numnodes; } density = (float)length / (float)area; for (x = net->xmin; x < net->xmax; x++) for (y = net->ymin; y < net->ymax; y++) Congestion[OGRID(x, y, 0)] += density; } maxval = 0.0; for (x = 0; x < NumChannelsX[0]; x++) { for (y = 0; y < NumChannelsY[0]; y++) { density = Congestion[OGRID(x, y, 0)]; if (density > maxval) maxval = density; } } norm = (float)(LONGSPAN - 1) / maxval; // Draw destination pins as blue squares for (x = 0; x < NumChannelsX[0]; x++) { xspc = (x + 1) * spacing - hspc; for (y = 0; y < NumChannelsY[0]; y++) { value = (int)(norm * Congestion[OGRID(x, y, 0)]); XSetForeground(dpy, gc, bluevector[value]); yspc = height - (y + 1) * spacing - hspc; XFillRectangle(dpy, buffer, gc, xspc, yspc, spacing, spacing); } } // Cleanup free(Congestion); } /*--------------------------------------*/ /* Draw one net on the display */ /*--------------------------------------*/ void draw_net(NET net, u_char single, int *lastlayer) { int i, xspc, yspc; int layer; SEG seg; ROUTE rt; if (dpy == NULL) return; // Draw all nets, much like "emit_routes" does when writing // routes to the DEF file. rt = net->routes; if (single && rt) for (rt = net->routes; rt->next; rt = rt->next); for (; rt; rt = rt->next) { for (seg = rt->segments; seg; seg = seg->next) { layer = seg->layer; if (layer != *lastlayer) { *lastlayer = layer; switch(layer) { case 0: XSetForeground(dpy, gc, bluepix); break; case 1: XSetForeground(dpy, gc, redpix); break; case 2: XSetForeground(dpy, gc, cyanpix); break; case 3: XSetForeground(dpy, gc, goldpix); break; default: XSetForeground(dpy, gc, greenpix); break; } } XDrawLine(dpy, buffer, gc, spacing * (seg->x1 + 1), height - spacing * (seg->y1 + 1), spacing * (seg->x2 + 1), height - spacing * (seg->y2 + 1)); if (single) XDrawLine(dpy, win, gc, spacing * (seg->x1 + 1), height - spacing * (seg->y1 + 1), spacing * (seg->x2 + 1), height - spacing * (seg->y2 + 1)); } } if (single) { // The following line to be removed XCopyArea(dpy, buffer, win, gc, 0, 0, width, height, 0, 0); XFlush(dpy); } } /*--------------------------------------*/ /* Graphical display of the layout */ /*--------------------------------------*/ void draw_layout() { int lastlayer, xspc, yspc, hspc; int i, x, y; NET net; NETLIST nlist; if (dpy == NULL) return; else if (buffer == (Pixmap)NULL) return; XSetForeground(dpy, gc, whitepix); XFillRectangle(dpy, buffer, gc, 0, 0, width, height); // Check if a netlist even exists if (Obs[0] == NULL) { XCopyArea(dpy, buffer, win, gc, 0, 0, width, height, 0, 0); return; } switch (mapType & MAP_MASK) { case MAP_OBSTRUCT: map_obstruction(); break; case MAP_CONGEST: map_congestion(); break; case MAP_ESTIMATE: map_estimate(); break; } // Draw all nets, much like "emit_routes" does when writing // routes to the DEF file. if ((mapType & DRAW_MASK) == DRAW_ROUTES) { lastlayer = -1; for (i = 0; i < Numnets; i++) { net = Nlnets[i]; draw_net(net, FALSE, &lastlayer); } } /* Copy double-buffer onto display window */ XCopyArea(dpy, buffer, win, gc, 0, 0, width, height, 0, 0); } /*--------------------------------------*/ /* GUI initialization */ /*--------------------------------------*/ int GUI_init(Tcl_Interp *interp) { Tk_Window tkwind, tktop; static char *qrouterdrawdefault = ".qrouter"; char *qrouterdrawwin; XColor cvcolor, cvexact; int i; float frac; tktop = Tk_MainWindow(interp); if (tktop == NULL) { tcl_printf(stderr, "No Top-level Tk window available. . .\n"); return; } qrouterdrawwin = (char *)Tcl_GetVar(interp, "drawwindow", TCL_GLOBAL_ONLY); if (qrouterdrawwin == NULL) qrouterdrawwin = qrouterdrawdefault; tkwind = Tk_NameToWindow(interp, qrouterdrawwin, tktop); if (tkwind == NULL) { tcl_printf(stderr, "The Tk window hierarchy must be rooted at " ".qrouter or $drawwindow must point to the drawing window\n"); return TCL_ERROR; } Tk_MapWindow(tkwind); dpy = Tk_Display(tkwind); win = Tk_WindowId(tkwind); cmap = DefaultColormap (dpy, Tk_ScreenNumber(tkwind)); load_font(&font_info); /* create GC for text and drawing */ createGC(win, &gc, font_info); /* Initialize colors */ XAllocNamedColor(dpy, cmap, "blue", &cvcolor, &cvexact); bluepix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "cyan", &cvcolor, &cvexact); cyanpix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "green", &cvcolor, &cvexact); greenpix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "red", &cvcolor, &cvexact); redpix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "orange", &cvcolor, &cvexact); orangepix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "gold", &cvcolor, &cvexact); goldpix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "gray70", &cvcolor, &cvexact); ltgraypix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "gray50", &cvcolor, &cvexact); graypix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "yellow", &cvcolor, &cvexact); yellowpix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "purple", &cvcolor, &cvexact); purplepix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "magenta", &cvcolor, &cvexact); magentapix = cvcolor.pixel; XAllocNamedColor(dpy, cmap, "GreenYellow", &cvcolor, &cvexact); greenyellowpix = cvcolor.pixel; blackpix = BlackPixel(dpy,DefaultScreen(dpy)); whitepix = WhitePixel(dpy,DefaultScreen(dpy)); cvcolor.flags = DoRed | DoGreen | DoBlue; for (i = 0; i < SHORTSPAN; i++) { frac = (float)i / (float)(SHORTSPAN - 1); /* gamma correction */ frac = pow(frac, 0.5); cvcolor.green = (int)(53970 * frac); cvcolor.blue = (int)(46260 * frac); cvcolor.red = (int)(35980 * frac); XAllocColor(dpy, cmap, &cvcolor); brownvector[i] = cvcolor.pixel; } cvcolor.green = 0; cvcolor.red = 0; for (i = 0; i < LONGSPAN; i++) { frac = (float)i / (float)(LONGSPAN - 1); /* gamma correction */ frac = pow(frac, 0.5); cvcolor.blue = (int)(65535 * frac); XAllocColor(dpy, cmap, &cvcolor); bluevector[i] = cvcolor.pixel; } return TCL_OK; /* proceed to interpreter */ } /*----------------------------------------------------------------*/ int QuitCallback(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *objv[]) { exit(0); return TCL_OK; // Statement not reached } /*----------------------------------------------------------------*/ void load_font(XFontStruct **font_info) { char *fontname = "9x15"; /* Load font and get font information structure. */ if ((*font_info = XLoadQueryFont (dpy,fontname)) == NULL) { (void) Fprintf (stderr, "Cannot open 9x15 font\n"); // exit(1); } } /*----------------------------------------------------------------*/ void createGC(Window win, GC *gc, XFontStruct *font_info) { unsigned long valuemask = 0; /* ignore XGCvalues and use defaults */ XGCValues values; unsigned int line_width = 1; int line_style = LineSolid; int cap_style = CapRound; int join_style = JoinRound; /* Create default Graphics Context */ *gc = XCreateGC(dpy, win, valuemask, &values); /* specify font */ if (font_info != NULL) XSetFont(dpy, *gc, font_info->fid); /* specify black foreground since default window background is * white and default foreground is undefined. */ XSetForeground(dpy, *gc, blackpix); /* set line, fill attributes */ XSetLineAttributes(dpy, *gc, line_width, line_style, cap_style, join_style); XSetFillStyle(dpy, *gc, FillSolid); XSetArcMode(dpy, *gc, ArcPieSlice); } /*----------------------------------------------------------------*/ void expose(Tk_Window tkwind) { if (Tk_WindowId(tkwind) == 0) return; if (dpy == NULL) return; draw_layout(); } /*----------------------------------------------------------------*/ int redraw(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *objv[]) { draw_layout(); return TCL_OK; } /*------------------------------------------------------*/ /* Call to recalculate the spacing if NumChannelsX[0] */ /* or NumChannelsY[0] changes. */ /* */ /* Return 1 if the spacing changed, 0 otherwise. */ /*------------------------------------------------------*/ int recalc_spacing() { int xspc, yspc; int oldspacing = spacing; xspc = width / (NumChannelsX[0] + 1); yspc = height / (NumChannelsY[0] + 1); spacing = (xspc < yspc) ? xspc : yspc; if (spacing == 0) spacing = 1; return (spacing == oldspacing) ? 0 : 1; } /*----------------------------------------------------------------*/ void resize(Tk_Window tkwind, int locwidth, int locheight) { Window window; if ((locwidth == 0) || (locheight == 0)) return; if (buffer != (Pixmap)0) XFreePixmap (Tk_Display(tkwind), buffer); if (Tk_WindowId(tkwind) == 0) Tk_MapWindow(tkwind); buffer = XCreatePixmap (Tk_Display(tkwind), Tk_WindowId(tkwind), locwidth, locheight, DefaultDepthOfScreen(Tk_Screen(tkwind))); width = locwidth; height = locheight; recalc_spacing(); if (dpy) draw_layout(); } /*----------------------------------------------------------------*/ qrouter-1.3.33/qrouter.h0000664000175000001440000003530312625401740013673 0ustar timusers/*--------------------------------------------------------------*/ /* qrouter.h -- general purpose autorouter */ /*--------------------------------------------------------------*/ /* Written by Steve Beccue, 2003 */ /* Modified by Tim Edwards 2011-2013 */ /*--------------------------------------------------------------*/ #ifndef QROUTER_H #define OGRID(x, y, layer) ((int)((x) + ((y) * NumChannelsX[(layer)]))) #define MIN(x, y) (((x) < (y)) ? (x) : (y)) #define MAX(x, y) (((x) > (y)) ? (x) : (y)) #define ABSDIFF(x, y) (((x) > (y)) ? ((x) - (y)) : ((y) - (x))) #define EPS 1e-4 // For handling round-off error; value // is in um (so 1e-4 = 0.1nm), should be // smaller than any feature size. // For handling round-off error on signed values. REPS(x) is x + EPS when // x is positive, and x - EPS when x is negative. #define REPS(x) (((x) < 0) ? ((x) - EPS) : ((x) + EPS)) #define TRUE 1 #define FALSE 0 #ifndef _SYS_TYPES_H #ifndef u_char typedef unsigned char u_char; #endif #ifndef u_short typedef unsigned short u_short; #endif #ifndef u_int typedef unsigned int u_int; #endif #ifndef u_long typedef unsigned long u_long; #endif #endif /* _SYS_TYPES_H */ /* Maximum number of route layers */ #define MAX_LAYERS 9 /* Maximum number of pins in a gate */ #define MAX_GATE_NODES 64 /* Cell name (and other names) max length */ #define MAX_NAME_LEN 1024 /* Max reasonable line length */ #define MAX_LINE_LEN 2048 /* Default configuration filename */ #define CONFIGFILENAME "route.cfg" // define possible gate orientations #define MNONE 0 #define MX 1 #define MY 2 // define search directions #define NORTH (u_char)1 #define SOUTH (u_char)2 #define EAST (u_char)3 #define WEST (u_char)4 #define UP (u_char)5 #define DOWN (u_char)6 // define types of via checkerboard patterns #define VIA_PATTERN_NONE -1 #define VIA_PATTERN_NORMAL 0 #define VIA_PATTERN_INVERT 1 // structure holding input and output scalefactors typedef struct scalerec_ { int iscale; double oscale; } ScaleRec; // define a structure containing x, y, and layer typedef struct gridp_ GRIDP; struct gridp_ { int x; int y; int lay; u_int cost; }; typedef struct proute_ PROUTE; struct proute_ { // partial route u_char flags; // values PR_PROCESSED and PR_CONFLICT, and others union { u_int cost; // cost of route coming from predecessor u_int net; // net number at route point } prdata; }; // Bit values for "flags" in PROUTE #define PR_PRED_DMASK 0x07 // Mask for directional bits #define PR_PRED_NONE 0x00 // This node does not have a predecessor #define PR_PRED_N 0x01 // Predecessor is north #define PR_PRED_S 0x02 // Predecessor is south #define PR_PRED_E 0x03 // Predecessor is east #define PR_PRED_W 0x04 // Predecessor is west #define PR_PRED_U 0x05 // Predecessor is up #define PR_PRED_D 0x06 // Predecessor is down #define PR_PROCESSED 0x08 // Tag to avoid visiting more than once #define PR_CONFLICT 0x10 // Two nets collide here during stage 2 #define PR_SOURCE 0x20 // This is a source node #define PR_TARGET 0x40 // This is a target node #define PR_COST 0x80 // if 1, use prdata.cost, not prdata.net // Linked string list typedef struct string_ *STRING; struct string_ { STRING next; char *name; }; /* Path segment information */ #define ST_WIRE 0x01 #define ST_VIA 0x02 #define ST_OFFSET_START 0x04 /* (x1, y1) is offset from grid */ #define ST_OFFSET_END 0x08 /* (x2, y2) is offset from grid */ #define ST_SPECIAL 0x10 /* wide metal (special net) */ typedef struct seg_ *SEG; struct seg_ { SEG next; int layer; int x1, y1, x2, y2; u_char segtype; }; /* DSEG is like a SEG, but coordinates are in microns (therefore type double) */ /* Used for gate node and obstruction positions. */ typedef struct dseg_ *DSEG; struct dseg_ { DSEG next; int layer; double x1, y1, x2, y2; }; /* POINT is an integer point in three dimensions (layer giving the */ /* vertical dimension). */ typedef struct point_ *POINT; struct point_ { POINT next; int layer; int x1, y1; }; /* DPOINT is a point location with coordinates given *both* as an */ /* integer (for the grid-based routing) and as a physical dimension */ /* (microns). */ typedef struct dpoint_ *DPOINT; struct dpoint_ { DPOINT next; int layer; double x, y; int gridx, gridy; }; typedef struct route_ *ROUTE; typedef struct node_ *NODE; struct route_ { ROUTE next; int netnum; SEG segments; u_char flags; // See below for flags }; /* Definitions for flags in struct route_ */ #define RT_OUTPUT 0x1 // Route has been output #define RT_STUB 0x2 // Route has been output struct node_ { NODE next; int nodenum; // node ordering within its net DPOINT taps; // point position for node taps DPOINT extend; // point position within halo of the tap char *netname; // name of net this node belongs to unsigned char numtaps; // number of actual reachable taps int netnum; // number of net this node belongs to int numnodes; // number of nodes on this net int branchx; // position of the node branch in x int branchy; // position of the node branch in y }; // these are instances of gates in the netlist. The description of a // given gate (the macro) is held in GateInfo. The same structure is // used for both the macro and the instance records. typedef struct gate_ *GATE; struct gate_ { GATE next; char *gatename; // Name of instance GATE gatetype; // Pointer to macro record int nodes; // number of nodes on this gate char *node[MAX_GATE_NODES]; // names of the pins on this gate int netnum[MAX_GATE_NODES]; // net number connected to each pin NODE noderec[MAX_GATE_NODES]; // node record for each pin DSEG taps[MAX_GATE_NODES]; // list of gate node locations and layers DSEG obs; // list of obstructions in gate double width, height; double placedX; double placedY; int orient; }; // Structure for a network to be routed typedef struct net_ *NET; typedef struct netlist_ *NETLIST; struct net_ { int netnum; // a unique number for this net char *netname; NODE netnodes; // list of nodes connected to the net int numnodes; // number of nodes connected to the net u_char flags; // flags for this net (see below) int netorder; // to be assigned by route strategy (critical // nets first, then order by number of nodes). int xmin, ymin; // Bounding box lower left corner int xmax, ymax; // Bounding box upper right corner int trunkx; // X position of the net's trunk line (see flags) int trunky; // Y position of the net's trunk line (see flags) NETLIST noripup; // list of nets that have been ripped up to // route this net. This will not be allowed // a second time, to avoid looping. ROUTE routes; // routes for this net }; // Flags used by NET "flags" record #define NET_PENDING 1 // pending being placed on "abandoned" list #define NET_CRITICAL 2 // net is in CriticalNet list #define NET_IGNORED 4 // net is ignored by router #define NET_STUB 8 // Net has at least one stub #define NET_VERTICAL_TRUNK 16 // Trunk line is (preferred) vertical // List of nets, used to maintain a list of failed routes struct netlist_ { NETLIST next; NET net; }; // A structure to hold information about source and target nets for // a route, to be passed between the route setup and execution stages struct routeinfo_ { NET net; ROUTE rt; POINT glist; NODE nsrc; DPOINT nsrctap; int maxcost; u_char do_pwrbus; int pwrbus_src; struct seg_ bbox; }; #define MAXRT 10000000 // "Infinite" route cost // The following values are added to the Obs[] structure for unobstructed // route positions close to a terminal, but not close enough to connect // directly. They describe which direction to go to reach the terminal. // The Stub[] vector indicates the distance needed to reach the terminal. // The OFFSET_TAP flag marks a position that is inside a terminal but // which needs to be adjusted in one direction to avoid a close obstruction. // The Stub[] vector indicates the distance needed to avoid the obstruction. // // The maximum number of nets must not overrun the area used by flags, so // the maximum number of nets is 0x1fffff, or 2,097,151 nets #define PINOBSTRUCTMASK ((u_int)0xe0000000) // takes values from below #define STUBROUTE_NS ((u_int)0x20000000) // route north or south to reach terminal #define STUBROUTE_EW ((u_int)0x40000000) // route east or west to reach terminal #define STUBROUTE_X ((u_int)0x60000000) // diagonal---not routable #define OFFSET_TAP ((u_int)0x80000000) // position needs to be offset #define NO_NET ((u_int)0x10000000) // indicates a non-routable obstruction #define BLOCKED_N ((u_int)0x08000000) // grid point cannot be routed from the N #define BLOCKED_S ((u_int)0x04000000) // grid point cannot be routed from the S #define BLOCKED_E ((u_int)0x02000000) // grid point cannot be routed from the E #define BLOCKED_W ((u_int)0x01000000) // grid point cannot be routed from the W #define BLOCKED_U ((u_int)0x00800000) // grid point cannot be routed from top #define BLOCKED_D ((u_int)0x00400000) // grid point cannot be routed from bottom #define BLOCKED_MASK ((u_int)0x0fc00000) #define ROUTED_NET ((u_int)0x00200000) // indicates position occupied by a routed // net #define MAX_NETNUMS ((u_int)0x001fffff) // Maximum net number #define NETNUM_MASK ((u_int)0x101fffff) // Mask for the net number field // (includes NO_NET) #define ROUTED_NET_MASK ((u_int)0x103fffff) // Mask for the net number field // (includes NO_NET and ROUTED_NET) #define DRC_BLOCKAGE (NO_NET | ROUTED_NET) // Special case // Definitions used along with the NO_NET bit. #define OBSTRUCT_MASK ((u_int)0x0000000f) // Tells where obstruction is #define OBSTRUCT_N ((u_int)0x00000008) // relative to the grid point. #define OBSTRUCT_S ((u_int)0x00000004) // Stub[] contains distance of #define OBSTRUCT_E ((u_int)0x00000002) // obstruction to grid point. #define OBSTRUCT_W ((u_int)0x00000001) // Map and draw modes #define MAP_NONE 0x0 // No map (blank background) #define MAP_OBSTRUCT 0x1 // Make a map of obstructions and pins #define MAP_CONGEST 0x2 // Make a map of congestion #define MAP_ESTIMATE 0x3 // Make a map of estimated congestion #define MAP_MASK 0x3 #define DRAW_NONE 0x0 // Draw only the background map #define DRAW_ROUTES 0x4 // Draw routes on top of background map #define DRAW_MASK 0x4 // Mask types (values other than 255 are interpreted as "slack" value) #define MASK_MINIMUM (u_char)0 // No slack #define MASK_SMALL (u_char)1 // Slack of +/-1 #define MASK_MEDIUM (u_char)2 // Slack of +/-2 #define MASK_LARGE (u_char)4 // Slack of +/-4 #define MASK_AUTO (u_char)253 // Choose best mask type #define MASK_BBOX (u_char)254 // Mask is simple bounding box #define MASK_NONE (u_char)255 // No mask used // Definitions of bits in needblock #define ROUTEBLOCKX (u_char)1 // Block adjacent routes in X #define ROUTEBLOCKY (u_char)2 // Block adjacent routes in Y #define VIABLOCKX (u_char)4 // Block adjacent vias in X #define VIABLOCKY (u_char)8 // Block adjacent vias in Y // Numnets + MIN_NET_NUMBER is guaranteed to be greater than the highest // number assigned to a net. #define MAXNETNUM (Numnets + MIN_NET_NUMBER) /* Global variables */ extern STRING DontRoute; extern STRING CriticalNet; extern NET CurNet; extern NETLIST FailedNets; // nets that have failed the first pass extern char DEFfilename[]; extern ScaleRec Scales; extern GATE GateInfo; // standard cell macro information extern GATE PinMacro; // macro definition for a pin extern GATE Nlgates; extern NET *Nlnets; extern u_char *RMask; extern u_int *Obs[MAX_LAYERS]; // obstructions by layer, y, x extern PROUTE *Obs2[MAX_LAYERS]; // working copy of Obs extern float *Obsinfo[MAX_LAYERS]; // temporary detailed obstruction info extern float *Stub[MAX_LAYERS]; // stub route distances to pins extern NODE *Nodeloc[MAX_LAYERS]; // nodes are attached to grid points // for reverse lookup extern NODE *Nodesav[MAX_LAYERS]; // copy of Nodeloc used for restoring // Nodeloc after net rip-up extern DSEG UserObs; // user-defined obstruction layers extern u_char needblock[MAX_LAYERS]; extern int Numnets; extern int Pinlayers; // Number of layers containing pin info. extern u_char Verbose; extern u_char keepTrying; extern u_char forceRoutable; extern u_char maskMode; extern u_char mapType; extern u_char ripLimit; extern char *vddnet; extern char *gndnet; /* Tcl output to console handling */ #ifdef TCL_QROUTER #define Fprintf tcl_printf #define Flush tcl_stdflush #define Vprintf tcl_vprintf #else #define Fprintf fprintf #define Flush fflush #define Vprintf vfprintf #endif /* Function prototypes */ extern int set_num_channels(); extern int allocate_obs_array(); void check_variable_pitch(int, int *, int *); NET getnettoroute(); int dofirststage(u_char graphdebug, int debug_netnum); int dosecondstage(u_char graphdebug, u_char singlestep); int route_net_ripup(NET net, u_char graphdebug); void read_lef(char *filename); void read_def(char *filename); int write_def(char *filename); int doroute(NET net, u_char stage, u_char graphdebug); int route_setup(struct routeinfo_ *iroute, u_char stage); int next_route_setup(struct routeinfo_ *iroute, u_char stage); int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug); ROUTE createemptyroute(); void emit_routes(char *filename, double oscale, int iscale); int set_routes_to_net(NET net, int newflags, POINT *pushlist, SEG bbox, u_char stage); int set_route_to_net(NET net, ROUTE rt, int newflags, POINT *pushlist, SEG bbox, u_char stage); void initMask(); void createMask(NET net, u_char slack, u_char halo); void fillMask(u_char value); void pathstart(FILE *cmd, int layer, int x, int y, u_char special, double oscale, double invscale, u_char horizontal); void pathto(FILE *cmd, int x, int y, int horizontal, int lastx, int lasty, double invscale); void pathvia(FILE *cmd, int layer, int x, int y, int lastx, int lasty, int gridx, int gridy, double invscale); void highlight_starts(POINT glist); void highlight_source(); void highlight_dest(); void highlight(int, int); int recalc_spacing(); void draw_layout(); void helpmessage(); void print_nets(char *filename); void print_routes(char *filename); void print_nlgates(char *filename); char *print_node_name(NODE node); GATE DefFindInstance(char *name); void DefHashInstance(GATE gateginfo); #define QROUTER_H #endif /* end of qrouter.h */ qrouter-1.3.33/lib/0000755000175000001440000000000012406043443012560 5ustar timusersqrouter-1.3.33/lib/route.cfg0000644000175000001440000000212612406043443014400 0ustar timusers# Route configuration file for OSU035 gate library # # Values are largely ignored in favor of those in the LEF file. # Cost information is required. Num_layers 3 Layer_1_name M1 Layer_2_name M2 Layer_3_name M3 Layer_1_width 0.8 Layer_2_width 0.8 Layer_3_width 0.8 Allow Adjacent Vias 1 layer 1 wire pitch 2.0 layer 2 wire pitch 1.6 layer 3 wire pitch 2.0 layer 1 horizontal layer 2 vertical layer 3 horizontal Num Passes 3 # Make sure 2 * Via Cost + Segment Cost > Jog Cost. # That prevents switching layers to move over one track position Route Segment Cost 2 Route Via Cost 10 Route Jog Cost 20 Route Crossover Cost 8 Route Block Cost 50 #Do not route these nets! (Perhaps power, clock ...) Do not route node vss Do not route node vdd #Route these nets first! Critical net! #Route Priority netxxx #Bounds for routes. This may not be the same as the gate boundries. X upper bound 1000.0 X lower bound 0 Y upper bound 1000.0 Y lower bound 0 # Complete gate information can be found here: lef ../lib/osu035_stdcells.lef qrouter-1.3.33/lib/osu035_stdcells.lef0000644000175000001440000023251712406043443016215 0ustar timusers# LEF file generated by Abstract Generator version 5.5.10 on Jul 30 14:47:58 2004 # # Contains LEF for all bins. # Options: [x] Antenna # [x] Geometry # [x] Technology VERSION 5.4 ; NAMESCASESENSITIVE ON ; BUSBITCHARS "[]" ; DIVIDERCHAR "/" ; UNITS DATABASE MICRONS 1000 ; END UNITS USEMINSPACING OBS ON ; USEMINSPACING PIN OFF ; CLEARANCEMEASURE EUCLIDEAN ; MANUFACTURINGGRID 0.1 ; LAYER nwell TYPE MASTERSLICE ; END nwell LAYER nactive TYPE MASTERSLICE ; END nactive LAYER pactive TYPE MASTERSLICE ; END pactive LAYER poly TYPE MASTERSLICE ; END poly LAYER cc TYPE CUT ; SPACING 0.9 ; END cc LAYER metal1 TYPE ROUTING ; DIRECTION HORIZONTAL ; PITCH 2 ; WIDTH 0.6 ; SPACING 0.6 ; RESISTANCE RPERSQ 0.07 ; CAPACITANCE CPERSQDIST 3e-05 ; END metal1 LAYER via TYPE CUT ; SPACING 0.6 ; END via LAYER metal2 TYPE ROUTING ; DIRECTION VERTICAL ; PITCH 1.6 ; WIDTH 0.6 ; SPACING 0.6 ; RESISTANCE RPERSQ 0.07 ; CAPACITANCE CPERSQDIST 1.7e-05 ; END metal2 LAYER via2 TYPE CUT ; SPACING 0.6 ; END via2 LAYER metal3 TYPE ROUTING ; DIRECTION HORIZONTAL ; PITCH 2 ; WIDTH 0.6 ; SPACING 0.6 ; RESISTANCE RPERSQ 0.07 ; CAPACITANCE CPERSQDIST 7e-06 ; END metal3 LAYER via3 TYPE CUT ; SPACING 0.8 ; END via3 LAYER metal4 TYPE ROUTING ; DIRECTION VERTICAL ; PITCH 3.2 ; WIDTH 1.2 ; SPACING 1.2 ; RESISTANCE RPERSQ 0.04 ; CAPACITANCE CPERSQDIST 4e-06 ; END metal4 VIA M2_M1 DEFAULT LAYER metal1 ; RECT -0.400 -0.400 0.400 0.400 ; LAYER via1 ; RECT -0.200 -0.200 0.200 0.200 ; LAYER metal2 ; RECT -0.400 -0.400 0.400 0.400 ; END M2_M1 VIA M3_M2 DEFAULT LAYER metal2 ; RECT -0.400 -0.400 0.400 0.400 ; LAYER via2 ; RECT -0.200 -0.200 0.200 0.200 ; LAYER metal3 ; RECT -0.400 -0.400 0.400 0.400 ; END M3_M2 VIA M4_M3 DEFAULT LAYER metal3 ; RECT -0.400 -0.400 0.400 0.400 ; LAYER via3 ; RECT -0.200 -0.200 0.200 0.200 ; LAYER metal4 ; RECT -0.600 -0.600 0.600 0.600 ; END M4_M3 VIARULE viagen21 GENERATE LAYER metal1 ; DIRECTION HORIZONTAL ; WIDTH 0.6 TO 60 ; OVERHANG 0.2 ; METALOVERHANG 0 ; LAYER metal2 ; DIRECTION VERTICAL ; WIDTH 0.6 TO 60 ; OVERHANG 0.2 ; METALOVERHANG 0 ; LAYER via1 ; RECT -0.2 -0.2 0.2 0.2 ; SPACING 1 BY 1 ; END viagen21 VIARULE viagen32 GENERATE LAYER metal3 ; DIRECTION HORIZONTAL ; WIDTH 0.6 TO 60 ; OVERHANG 0.2 ; METALOVERHANG 0 ; LAYER metal2 ; DIRECTION VERTICAL ; WIDTH 0.6 TO 60 ; OVERHANG 0.2 ; METALOVERHANG 0 ; LAYER via2 ; RECT -0.2 -0.2 0.2 0.2 ; SPACING 1 BY 1 ; END viagen32 VIARULE viagen43 GENERATE LAYER metal3 ; DIRECTION HORIZONTAL ; WIDTH 0.6 TO 60 ; OVERHANG 0.4 ; METALOVERHANG 0 ; LAYER metal4 ; DIRECTION VERTICAL ; WIDTH 0.6 TO 60 ; OVERHANG 0.4 ; METALOVERHANG 0 ; LAYER via3 ; RECT -0.2 -0.2 0.2 0.2 ; SPACING 1.2 BY 1.2 ; END viagen43 VIARULE TURN1 GENERATE LAYER metal1 ; DIRECTION HORIZONTAL ; LAYER metal1 ; DIRECTION VERTICAL ; END TURN1 VIARULE TURN2 GENERATE LAYER metal2 ; DIRECTION HORIZONTAL ; LAYER metal2 ; DIRECTION VERTICAL ; END TURN2 VIARULE TURN3 GENERATE LAYER metal3 ; DIRECTION HORIZONTAL ; LAYER metal3 ; DIRECTION VERTICAL ; END TURN3 VIARULE TURN4 GENERATE LAYER metal4 ; DIRECTION HORIZONTAL ; LAYER metal4 ; DIRECTION VERTICAL ; END TURN4 SITE corner CLASS PAD ; SYMMETRY R90 Y ; SIZE 300.000 BY 300.000 ; END corner SITE IO CLASS PAD ; SYMMETRY Y ; SIZE 90.000 BY 300.000 ; END IO SITE core CLASS CORE ; SYMMETRY Y ; SIZE 1.600 BY 20.000 ; END core MACRO FILL CLASS CORE ; FOREIGN FILL 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 1.600 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT -0.400 -0.600 2.000 0.600 ; END END gnd PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT -0.400 19.400 2.000 20.600 ; END END vdd END FILL MACRO AND2X1 CLASS CORE ; FOREIGN AND2X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 6.400 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 6.600 1.200 8.200 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.600 9.800 3.400 11.400 ; RECT 2.000 10.600 3.400 11.400 ; END END B PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 3.000 -0.600 3.800 5.200 ; RECT -0.400 -0.600 6.800 0.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 5.200 12.600 6.000 13.400 ; RECT 5.200 14.800 6.000 18.800 ; RECT 5.400 3.200 6.000 18.800 ; RECT 4.600 1.200 5.400 3.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 14.800 1.200 20.600 ; RECT -0.400 19.400 6.800 20.600 ; RECT 3.600 14.800 4.400 20.600 ; END END vdd OBS LAYER metal1 ; RECT 0.400 1.200 1.200 5.200 ; RECT 0.600 5.200 2.400 5.800 ; RECT 1.800 5.200 2.400 6.600 ; RECT 4.000 5.800 4.800 6.600 ; RECT 1.800 6.000 4.800 6.600 ; RECT 4.000 5.800 4.600 14.200 ; RECT 2.200 13.600 4.600 14.200 ; RECT 2.200 13.600 2.800 18.800 ; RECT 2.000 14.800 2.800 18.800 ; END END AND2X1 MACRO AND2X2 CLASS CORE ; FOREIGN AND2X2 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 6.400 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 6.600 1.200 8.200 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.200 7.200 2.800 9.400 ; RECT 2.400 7.000 3.200 7.800 ; RECT 2.000 8.600 2.800 9.400 ; END END B PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 3.000 -0.600 3.800 5.000 ; RECT -0.400 -0.600 6.800 0.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 5.200 8.600 6.000 9.400 ; RECT 5.200 10.800 6.000 18.800 ; RECT 5.400 4.200 6.000 18.800 ; RECT 4.600 1.200 5.400 5.200 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 14.800 1.200 20.600 ; RECT -0.400 19.400 6.800 20.600 ; RECT 3.600 11.200 4.400 20.600 ; END END vdd OBS LAYER metal1 ; RECT 0.400 1.200 1.200 5.200 ; RECT 0.600 1.200 1.200 6.000 ; RECT 0.600 5.400 2.400 6.000 ; RECT 1.800 5.800 4.800 6.400 ; RECT 4.000 5.800 4.800 6.600 ; RECT 4.000 5.800 4.600 10.600 ; RECT 2.200 10.000 4.600 10.600 ; RECT 2.200 10.000 2.800 18.800 ; RECT 2.000 14.800 2.800 18.800 ; END END AND2X2 MACRO AOI21X1 CLASS CORE ; FOREIGN AOI21X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 6.400 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 8.600 1.200 9.400 ; RECT 1.200 8.800 2.000 9.800 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.000 6.600 2.800 8.200 ; END END B PIN C DIRECTION INPUT ; PORT LAYER metal1 ; RECT 5.000 3.800 5.800 4.600 ; RECT 5.200 4.600 6.000 5.400 ; END END C PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 1.000 -0.600 1.800 5.200 ; RECT -0.400 -0.600 6.800 0.600 ; RECT 5.200 -0.600 6.000 3.200 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 3.600 1.200 4.200 9.400 ; RECT 5.200 10.800 6.000 18.800 ; RECT 3.600 8.800 6.000 9.400 ; RECT 5.200 8.600 6.000 9.400 ; RECT 5.200 8.600 5.800 18.800 ; RECT 3.600 1.200 4.400 5.200 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 12.000 2.800 20.600 ; RECT -0.400 19.400 6.800 20.600 ; END END vdd OBS LAYER metal1 ; RECT 0.400 10.800 4.400 11.400 ; RECT 0.400 10.800 1.200 18.800 ; RECT 3.600 10.800 4.400 18.800 ; END END AOI21X1 MACRO AOI22X1 CLASS CORE ; FOREIGN AOI22X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 8.000 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 8.600 1.200 9.400 ; RECT 1.200 8.800 2.000 9.800 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.000 6.600 2.800 8.200 ; END END B PIN C DIRECTION INPUT ; PORT LAYER metal1 ; RECT 6.800 8.600 7.600 10.200 ; END END C PIN D DIRECTION INPUT ; PORT LAYER metal1 ; RECT 5.200 6.600 5.800 8.600 ; RECT 5.200 6.600 6.000 7.400 ; RECT 5.000 7.800 5.800 8.600 ; END END D PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.800 -0.600 1.600 5.200 ; RECT -0.400 -0.600 8.400 0.600 ; RECT 6.800 -0.600 7.600 5.200 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 3.600 8.600 4.400 9.400 ; RECT 5.200 10.800 6.000 17.600 ; RECT 5.200 9.600 5.800 17.600 ; RECT 3.800 9.600 5.800 10.200 ; RECT 3.400 1.200 5.000 5.200 ; RECT 3.800 1.200 4.400 10.200 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 12.000 2.800 20.600 ; RECT -0.400 19.400 8.400 20.600 ; END END vdd OBS LAYER metal1 ; RECT 0.400 10.800 4.400 11.400 ; RECT 3.600 10.800 4.400 18.800 ; RECT 0.400 10.800 1.200 18.800 ; RECT 6.800 10.800 7.600 18.800 ; RECT 3.600 18.200 7.600 18.800 ; END END AOI22X1 MACRO BUFX2 CLASS CORE ; FOREIGN BUFX2 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 4.800 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 7.800 1.200 9.400 ; END END A PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 -0.600 2.800 5.200 ; RECT -0.400 -0.600 5.200 0.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 3.600 1.200 4.400 8.600 ; RECT 3.600 10.800 4.400 18.800 ; RECT 3.800 1.200 4.400 18.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 12.000 2.800 20.600 ; RECT -0.400 19.400 5.200 20.600 ; END END vdd OBS LAYER metal1 ; RECT 0.400 1.200 1.200 6.400 ; RECT 0.400 5.800 2.600 6.400 ; RECT 2.000 9.400 3.200 10.200 ; RECT 2.000 5.800 2.600 11.400 ; RECT 0.400 10.800 2.600 11.400 ; RECT 0.400 10.800 1.200 18.800 ; END END BUFX2 MACRO BUFX4 CLASS CORE ; FOREIGN BUFX4 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 6.400 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.600 7.800 1.400 9.400 ; RECT 0.400 8.600 1.400 9.400 ; END END A PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 -0.600 2.800 5.200 ; RECT -0.400 -0.600 6.800 0.600 ; RECT 5.200 -0.600 6.000 5.200 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 3.600 1.200 4.400 5.200 ; RECT 4.000 4.600 4.600 11.800 ; RECT 3.600 10.800 4.400 18.800 ; RECT 3.600 6.600 4.600 7.400 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 12.000 2.800 20.600 ; RECT -0.400 19.400 6.800 20.600 ; RECT 5.200 10.800 6.000 20.600 ; END END vdd OBS LAYER metal1 ; RECT 0.400 1.200 1.200 6.400 ; RECT 0.400 5.800 3.000 6.400 ; RECT 2.400 8.000 3.400 8.800 ; RECT 2.400 5.800 3.000 11.400 ; RECT 0.400 10.800 3.000 11.400 ; RECT 0.400 10.800 1.200 18.800 ; END END BUFX4 MACRO DFFNEGX1 CLASS CORE ; FOREIGN DFFNEGX1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 19.200 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN Q DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 14.600 9.400 15.400 10.200 ; RECT 18.000 1.200 18.800 18.800 ; RECT 14.600 9.600 18.800 10.200 ; RECT 15.000 5.600 18.800 6.200 ; RECT 15.000 5.400 15.800 6.200 ; END END Q PIN CLK DIRECTION INPUT ; PORT LAYER metal2 ; RECT 5.200 6.800 6.000 13.400 ; LAYER via1 ; RECT 5.400 12.800 5.800 13.200 ; RECT 5.400 7.000 5.800 7.400 ; LAYER metal1 ; RECT 5.200 12.600 6.000 13.400 ; RECT 1.200 6.800 12.800 7.400 ; RECT 12.000 6.600 12.800 7.400 ; RECT 5.200 6.800 6.000 7.600 ; RECT 4.200 4.600 5.000 5.400 ; RECT 4.000 5.400 4.800 7.400 ; RECT 1.200 6.600 2.800 7.400 ; RECT 5.400 13.400 6.200 14.200 ; END END CLK PIN D DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.800 8.400 3.600 9.200 ; RECT 6.800 8.600 7.600 9.400 ; RECT 2.800 8.600 7.600 9.200 ; END END D PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 -0.600 2.800 5.200 ; RECT -0.400 -0.600 19.600 0.600 ; RECT 16.400 -0.600 17.200 5.000 ; RECT 10.800 -0.600 11.600 3.200 ; RECT 7.400 -0.600 8.400 3.200 ; END END gnd PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 11.000 2.800 20.600 ; RECT -0.400 19.400 19.600 20.600 ; RECT 16.400 10.800 17.200 20.600 ; RECT 10.800 14.800 11.600 20.600 ; RECT 7.600 14.800 8.400 20.600 ; END END vdd OBS LAYER metal2 ; RECT 0.400 5.200 1.200 10.800 ; RECT 3.600 3.200 4.400 10.000 ; RECT 3.600 3.200 4.200 14.800 ; RECT 3.600 10.800 4.400 14.800 ; RECT 13.200 3.200 14.000 11.400 ; RECT 13.200 3.200 13.800 14.800 ; RECT 13.200 12.200 14.000 14.800 ; LAYER metal1 ; RECT 0.400 1.200 1.200 6.000 ; RECT 3.600 14.000 4.400 15.400 ; RECT 3.600 14.800 5.600 15.400 ; RECT 4.800 14.800 5.600 18.800 ; RECT 4.800 1.200 5.600 3.200 ; RECT 3.600 2.600 5.600 3.200 ; RECT 3.600 2.600 4.400 4.000 ; RECT 3.600 11.400 9.000 12.000 ; RECT 3.600 11.400 4.400 12.200 ; RECT 8.200 11.400 9.000 12.200 ; RECT 9.200 1.200 10.000 3.200 ; RECT 9.200 1.200 9.800 4.400 ; RECT 7.000 3.800 9.800 4.400 ; RECT 7.000 3.800 7.800 4.600 ; RECT 7.000 13.400 7.800 14.200 ; RECT 9.800 13.400 10.600 14.200 ; RECT 7.000 13.600 10.600 14.200 ; RECT 9.200 13.600 9.800 18.800 ; RECT 9.200 14.800 10.000 18.800 ; RECT 13.200 14.000 14.000 14.800 ; RECT 13.400 14.800 14.600 18.800 ; RECT 0.400 9.800 5.000 10.400 ; RECT 4.200 10.200 11.400 10.800 ; RECT 10.800 10.200 11.400 12.200 ; RECT 10.800 11.400 14.600 12.000 ; RECT 10.800 11.400 11.800 12.200 ; RECT 13.800 11.400 14.600 12.200 ; RECT 0.400 9.800 1.200 18.800 ; RECT 13.400 1.200 14.600 3.200 ; RECT 13.200 2.600 14.000 4.000 ; RECT 13.200 8.000 14.000 8.800 ; RECT 13.200 8.200 17.000 8.800 ; RECT 16.200 8.200 17.000 9.000 ; LAYER via1 ; RECT 0.600 10.200 1.000 10.600 ; RECT 0.600 5.400 1.000 5.800 ; RECT 3.800 14.200 4.200 14.600 ; RECT 3.800 11.600 4.200 12.000 ; RECT 3.800 3.400 4.200 3.800 ; RECT 13.400 14.200 13.800 14.600 ; RECT 13.400 8.200 13.800 8.600 ; RECT 13.400 3.400 13.800 3.800 ; END END DFFNEGX1 MACRO NOR3X1 CLASS CORE ; FOREIGN NOR3X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 12.800 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.000 4.600 3.800 5.400 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 3.600 6.600 5.200 7.400 ; END END B PIN C DIRECTION INPUT ; PORT LAYER metal1 ; RECT 5.200 8.600 6.800 9.400 ; END END C PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 -0.600 2.800 3.200 ; RECT -0.400 -0.600 13.200 0.600 ; RECT 5.200 -0.600 6.000 2.800 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 3.600 1.200 4.400 3.200 ; RECT 10.000 12.000 10.800 17.600 ; RECT 10.000 10.600 10.800 11.400 ; RECT 10.000 10.600 10.600 17.600 ; RECT 7.400 10.600 10.800 11.200 ; RECT 7.400 3.200 8.000 11.200 ; RECT 6.800 1.200 7.600 4.000 ; RECT 4.000 3.400 8.000 4.000 ; RECT 4.000 2.600 4.600 4.000 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 12.800 2.800 20.600 ; RECT -0.400 19.400 13.200 20.600 ; END END vdd OBS LAYER metal1 ; RECT 0.600 11.600 4.200 12.200 ; RECT 3.600 11.600 4.200 18.800 ; RECT 3.600 12.800 4.400 18.800 ; RECT 0.600 11.600 1.200 18.800 ; RECT 0.400 12.800 1.200 18.800 ; RECT 6.800 13.000 7.600 18.800 ; RECT 3.600 18.200 7.600 18.800 ; RECT 5.400 11.800 9.000 12.400 ; RECT 5.400 11.800 6.000 17.600 ; RECT 5.200 12.800 6.000 17.600 ; RECT 8.400 12.000 9.200 18.000 ; RECT 11.600 12.000 12.400 18.000 ; RECT 8.600 12.000 9.200 18.800 ; RECT 11.600 12.000 12.200 18.800 ; RECT 8.600 18.200 12.200 18.800 ; END END NOR3X1 MACRO DFFPOSX1 CLASS CORE ; FOREIGN DFFPOSX1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 19.200 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN Q DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 14.600 9.400 15.400 10.200 ; RECT 18.000 1.200 18.800 18.800 ; RECT 14.600 9.600 18.800 10.200 ; RECT 15.000 5.600 18.800 6.200 ; RECT 15.000 5.400 15.800 6.200 ; END END Q PIN CLK DIRECTION INPUT ; PORT LAYER metal1 ; RECT 1.200 6.600 2.800 7.400 ; RECT 13.400 12.200 14.800 13.000 ; RECT 13.400 10.600 14.000 13.000 ; RECT 11.600 10.600 14.000 11.200 ; RECT 11.600 6.800 12.200 11.200 ; RECT 11.000 6.600 11.800 7.400 ; RECT 1.200 6.800 12.200 7.400 ; RECT 5.400 3.800 6.000 7.400 ; RECT 5.200 3.800 6.000 4.600 ; RECT 4.200 6.800 5.000 7.600 ; END END CLK PIN D DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.600 8.400 3.400 9.200 ; RECT 6.800 8.600 7.600 9.400 ; RECT 2.600 8.600 7.600 9.200 ; END END D PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 -0.600 2.800 5.200 ; RECT -0.400 -0.600 19.600 0.600 ; RECT 16.400 -0.600 17.200 5.000 ; RECT 10.800 -0.600 11.600 3.200 ; RECT 7.400 -0.600 8.400 3.200 ; END END gnd PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 11.000 2.800 20.600 ; RECT -0.400 19.400 19.600 20.600 ; RECT 16.400 10.800 17.200 20.600 ; RECT 10.800 14.800 11.600 20.600 ; RECT 7.600 14.800 8.400 20.600 ; END END vdd OBS LAYER metal2 ; RECT 0.400 5.200 1.200 10.800 ; RECT 3.600 3.200 4.400 14.800 ; RECT 13.200 3.200 14.000 14.800 ; LAYER metal1 ; RECT 0.400 1.200 1.200 6.000 ; RECT 3.600 14.000 4.400 15.400 ; RECT 3.600 14.800 5.600 15.400 ; RECT 4.800 14.800 5.600 18.800 ; RECT 4.800 1.200 5.600 3.200 ; RECT 3.600 2.600 5.600 3.200 ; RECT 3.600 2.600 4.400 4.000 ; RECT 3.600 11.400 9.000 12.000 ; RECT 3.600 11.400 4.400 12.200 ; RECT 8.200 11.400 9.000 12.200 ; RECT 9.200 1.200 10.000 3.200 ; RECT 9.200 1.200 9.800 4.400 ; RECT 7.000 3.800 9.800 4.400 ; RECT 7.000 3.800 7.800 4.600 ; RECT 7.000 13.400 7.800 14.200 ; RECT 9.800 13.400 10.600 14.200 ; RECT 7.000 13.600 10.600 14.200 ; RECT 9.200 13.600 9.800 18.800 ; RECT 9.200 14.800 10.000 18.800 ; RECT 0.400 10.000 6.200 10.400 ; RECT 0.400 9.800 6.000 10.400 ; RECT 5.400 10.200 10.200 10.800 ; RECT 9.600 10.200 10.200 12.600 ; RECT 11.000 11.800 11.800 12.600 ; RECT 9.600 12.000 11.800 12.600 ; RECT 0.400 9.800 1.200 18.800 ; RECT 13.200 14.000 14.000 14.800 ; RECT 13.400 14.800 14.600 18.800 ; RECT 13.400 1.200 14.600 3.200 ; RECT 13.200 2.600 14.000 4.000 ; RECT 13.200 8.000 14.000 8.800 ; RECT 13.200 8.200 17.000 8.800 ; RECT 16.200 8.200 17.000 9.000 ; LAYER via1 ; RECT 0.600 10.200 1.000 10.600 ; RECT 0.600 5.400 1.000 5.800 ; RECT 3.800 14.200 4.200 14.600 ; RECT 3.800 11.600 4.200 12.000 ; RECT 3.800 3.400 4.200 3.800 ; RECT 13.400 14.200 13.800 14.600 ; RECT 13.400 8.200 13.800 8.600 ; RECT 13.400 3.400 13.800 3.800 ; END END DFFPOSX1 MACRO FAX1 CLASS CORE ; FOREIGN FAX1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 24.000 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN YC DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 22.800 1.200 23.600 3.200 ; RECT 22.800 14.800 23.600 18.800 ; RECT 23.000 1.200 23.600 18.800 ; RECT 22.800 6.600 23.600 7.400 ; END END YC PIN YS DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 19.600 1.200 20.400 3.200 ; RECT 20.800 4.600 22.000 5.400 ; RECT 19.400 9.200 21.400 9.800 ; RECT 20.800 3.800 21.400 9.800 ; RECT 19.800 3.800 21.400 4.400 ; RECT 19.600 14.800 20.400 18.800 ; RECT 19.800 1.200 20.400 4.400 ; RECT 19.400 9.200 20.000 15.400 ; END END YS PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.600 6.000 2.000 6.600 ; RECT 17.800 6.800 18.600 7.600 ; RECT 17.800 5.600 18.400 7.600 ; RECT 7.400 5.600 18.400 6.200 ; RECT 0.600 6.000 8.200 6.400 ; RECT 1.200 5.800 18.400 6.200 ; RECT 0.400 6.600 1.200 7.400 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.200 7.200 2.800 9.400 ; RECT 16.000 6.800 16.800 7.600 ; RECT 9.400 6.800 16.800 7.400 ; RECT 2.200 7.200 10.200 7.600 ; RECT 2.800 7.000 16.800 7.400 ; RECT 5.800 7.000 6.600 7.800 ; RECT 2.200 7.200 3.600 7.800 ; RECT 2.000 8.600 2.800 9.400 ; END END B PIN C DIRECTION INPUT ; PORT LAYER metal1 ; RECT 3.600 8.600 5.200 9.400 ; RECT 14.400 8.000 15.200 8.800 ; RECT 10.400 8.200 15.200 8.800 ; RECT 3.600 8.600 11.800 9.000 ; RECT 3.600 8.600 11.000 9.200 ; END END C PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 -0.600 2.800 4.000 ; RECT -0.400 -0.600 24.400 0.600 ; RECT 21.200 -0.600 22.000 3.200 ; RECT 18.000 -0.600 18.800 5.000 ; RECT 11.000 -0.600 11.800 3.800 ; RECT 7.800 -0.600 8.600 4.800 ; END END gnd PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 12.000 2.800 20.600 ; RECT -0.400 19.400 24.400 20.600 ; RECT 21.200 14.800 22.000 20.600 ; RECT 18.000 9.200 18.800 20.600 ; RECT 11.000 12.800 11.800 20.600 ; RECT 7.800 10.800 8.600 20.600 ; END END vdd OBS LAYER metal2 ; RECT 14.400 4.200 15.200 5.000 ; RECT 14.600 7.800 20.200 8.400 ; RECT 19.400 7.800 20.200 8.600 ; RECT 14.600 4.200 15.200 10.200 ; RECT 14.400 9.400 15.200 10.200 ; RECT 5.200 4.400 6.000 5.200 ; RECT 12.000 9.600 12.800 11.400 ; RECT 20.800 10.600 21.600 11.400 ; RECT 5.200 10.800 21.600 11.400 ; RECT 5.400 4.400 6.000 11.600 ; RECT 5.200 10.800 6.000 11.600 ; LAYER metal1 ; RECT 0.400 10.800 4.400 11.400 ; RECT 0.400 10.800 1.200 18.800 ; RECT 3.600 10.800 4.400 18.800 ; RECT 0.400 1.200 1.200 5.200 ; RECT 3.600 1.200 4.400 5.200 ; RECT 0.400 4.600 4.400 5.200 ; RECT 5.200 10.800 6.000 18.800 ; RECT 5.200 1.200 6.000 5.200 ; RECT 9.400 11.600 13.400 12.200 ; RECT 9.400 10.800 10.200 18.800 ; RECT 12.600 11.600 13.400 18.800 ; RECT 9.400 1.200 10.200 5.000 ; RECT 12.600 1.200 13.400 5.000 ; RECT 9.400 4.400 13.400 5.000 ; RECT 12.800 9.400 13.600 10.200 ; RECT 12.000 9.600 12.800 10.400 ; RECT 14.400 9.400 15.200 18.800 ; RECT 14.200 10.200 15.200 18.800 ; RECT 14.200 1.200 15.200 4.200 ; RECT 14.400 1.200 15.200 5.000 ; RECT 19.400 7.000 20.200 8.600 ; RECT 20.800 10.600 22.400 11.400 ; LAYER via1 ; RECT 5.400 11.000 5.800 11.400 ; RECT 5.400 4.600 5.800 5.000 ; RECT 12.200 9.800 12.600 10.200 ; RECT 14.600 9.600 15.000 10.000 ; RECT 14.600 4.400 15.000 4.800 ; RECT 19.600 8.000 20.000 8.400 ; RECT 21.000 10.800 21.400 11.200 ; END END FAX1 MACRO HAX1 CLASS CORE ; FOREIGN HAX1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 16.000 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN YC DIRECTION OUTPUT ; PORT LAYER metal2 ; RECT 4.600 3.200 6.000 4.000 ; RECT 5.200 8.400 6.000 9.200 ; RECT 5.400 3.200 6.000 9.200 ; LAYER via1 ; RECT 4.800 3.400 5.200 3.800 ; RECT 5.400 8.600 5.800 9.000 ; LAYER metal1 ; RECT 4.600 1.200 5.400 4.000 ; RECT 5.200 8.400 6.000 18.800 ; END END YC PIN YS DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 13.200 10.600 14.000 11.400 ; RECT 14.200 14.800 15.000 18.800 ; RECT 14.400 13.600 15.000 18.800 ; RECT 13.400 4.000 15.000 4.600 ; RECT 14.400 1.200 15.000 4.600 ; RECT 13.400 13.600 15.000 14.200 ; RECT 14.200 1.200 15.000 3.200 ; RECT 13.400 4.000 14.000 14.200 ; END END YS PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 6.000 1.200 7.400 ; RECT 10.000 6.600 10.800 7.400 ; RECT 8.400 6.600 10.800 7.200 ; RECT 0.400 6.000 9.000 6.600 ; RECT 0.800 5.800 1.600 6.600 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.200 8.000 3.000 8.600 ; RECT 8.400 7.800 9.200 8.600 ; RECT 7.200 7.800 9.200 8.400 ; RECT 2.400 7.200 7.800 7.800 ; RECT 2.400 7.200 3.200 8.000 ; RECT 2.000 8.600 2.800 9.400 ; END END B PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 5.200 ; RECT -0.400 -0.600 16.400 0.600 ; RECT 12.600 -0.600 13.400 3.200 ; RECT 6.200 -0.600 7.000 5.000 ; END END gnd PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 15.200 2.800 20.600 ; RECT -0.400 19.400 16.400 20.600 ; RECT 12.600 14.800 13.400 20.600 ; RECT 11.000 10.800 11.800 20.600 ; RECT 6.800 14.800 7.600 20.600 ; END END vdd OBS LAYER metal2 ; RECT 3.800 4.600 4.600 5.400 ; RECT 3.800 4.600 4.400 9.200 ; RECT 3.800 8.400 4.600 9.200 ; LAYER metal1 ; RECT 3.800 8.400 4.600 9.200 ; RECT 0.600 14.000 4.400 14.600 ; RECT 0.600 14.000 1.200 18.800 ; RECT 0.400 14.800 1.200 18.800 ; RECT 3.800 8.400 4.400 18.800 ; RECT 3.600 14.000 4.400 18.800 ; RECT 3.000 1.200 3.800 5.200 ; RECT 3.800 4.600 5.600 5.400 ; RECT 7.800 1.200 11.800 1.800 ; RECT 11.000 1.200 11.800 4.800 ; RECT 7.800 1.200 8.600 5.200 ; RECT 9.400 2.400 10.200 5.200 ; RECT 9.600 2.400 10.200 6.000 ; RECT 9.600 5.400 12.600 6.000 ; RECT 11.400 5.400 12.600 6.200 ; RECT 11.400 5.400 12.000 10.200 ; RECT 8.600 9.600 12.000 10.200 ; RECT 8.600 9.600 9.200 18.800 ; RECT 8.400 10.800 9.200 18.800 ; LAYER via1 ; RECT 4.000 8.600 4.400 9.000 ; RECT 4.000 4.800 4.400 5.200 ; END END HAX1 MACRO INVX1 CLASS CORE ; FOREIGN INVX1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 3.200 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 3.800 1.200 5.400 ; END END A PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 3.200 ; RECT -0.400 -0.600 3.600 0.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 2.000 1.200 2.800 18.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 14.800 1.200 20.600 ; RECT -0.400 19.400 3.600 20.600 ; END END vdd END INVX1 MACRO INVX2 CLASS CORE ; FOREIGN INVX2 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 3.200 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 5.800 1.200 7.400 ; END END A PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 5.200 ; RECT -0.400 -0.600 3.600 0.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 2.000 1.200 2.800 18.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 10.800 1.200 20.600 ; RECT -0.400 19.400 3.600 20.600 ; END END vdd END INVX2 MACRO INVX4 CLASS CORE ; FOREIGN INVX4 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 4.800 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 5.800 1.200 7.400 ; END END A PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 5.200 ; RECT -0.400 -0.600 5.200 0.600 ; RECT 3.600 -0.600 4.400 5.200 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 2.000 1.200 2.800 18.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 10.800 1.200 20.600 ; RECT -0.400 19.400 5.200 20.600 ; RECT 3.600 10.800 4.400 20.600 ; END END vdd END INVX4 MACRO INVX8 CLASS CORE ; FOREIGN INVX8 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 8.000 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 5.800 1.200 7.400 ; END END A PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 5.200 ; RECT -0.400 -0.600 8.400 0.600 ; RECT 6.800 -0.600 7.600 5.200 ; RECT 3.600 -0.600 4.400 5.200 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 2.000 1.200 2.800 6.600 ; RECT 5.200 1.200 6.000 18.800 ; RECT 2.000 9.400 6.000 10.200 ; RECT 2.000 5.800 6.000 6.600 ; RECT 2.000 9.400 2.800 18.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 10.800 1.200 20.600 ; RECT -0.400 19.400 8.400 20.600 ; RECT 6.800 10.800 7.600 20.600 ; RECT 3.600 10.800 4.400 20.600 ; END END vdd END INVX8 MACRO NAND2X1 CLASS CORE ; FOREIGN NAND2X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 4.800 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 5.800 1.200 7.400 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 3.600 10.600 4.400 12.200 ; END END B PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 5.200 ; RECT -0.400 -0.600 5.200 0.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 2.000 4.600 2.800 18.800 ; RECT 2.000 4.600 3.800 5.200 ; RECT 3.000 1.200 3.800 5.200 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 14.800 1.200 20.600 ; RECT -0.400 19.400 5.200 20.600 ; RECT 3.600 14.800 4.400 20.600 ; END END vdd END NAND2X1 MACRO NAND3X1 CLASS CORE ; FOREIGN NAND3X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 6.400 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 9.800 1.200 11.400 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.000 8.600 3.600 9.400 ; END END B PIN C DIRECTION INPUT ; PORT LAYER metal1 ; RECT 3.600 11.800 4.400 13.400 ; END END C PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 7.200 ; RECT -0.400 -0.600 6.800 0.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 2.200 14.000 2.800 18.800 ; RECT 5.200 14.800 6.000 18.800 ; RECT 5.200 10.600 6.000 11.400 ; RECT 5.200 6.800 5.800 18.800 ; RECT 2.200 14.000 5.800 14.600 ; RECT 4.200 6.800 5.800 7.400 ; RECT 4.000 1.200 4.800 7.200 ; RECT 2.000 14.800 2.800 18.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 14.800 1.200 20.600 ; RECT -0.400 19.400 6.800 20.600 ; RECT 3.600 15.200 4.400 20.600 ; END END vdd END NAND3X1 MACRO NOR2X1 CLASS CORE ; FOREIGN NOR2X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 4.800 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 3.800 1.200 5.400 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 3.600 8.600 4.400 10.200 ; END END B PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 3.200 ; RECT -0.400 -0.600 5.200 0.600 ; RECT 3.600 -0.600 4.400 3.200 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 2.000 1.200 2.800 3.200 ; RECT 3.000 10.800 3.800 18.800 ; RECT 2.000 10.800 3.800 11.600 ; RECT 2.200 1.200 2.800 11.600 ; RECT 2.000 6.600 2.800 7.400 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 10.800 1.200 20.600 ; RECT -0.400 19.400 5.200 20.600 ; END END vdd END NOR2X1 MACRO OAI21X1 CLASS CORE ; FOREIGN OAI21X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 6.400 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 6.600 1.200 7.400 ; RECT 1.200 6.200 2.000 7.200 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.000 7.800 2.800 9.400 ; END END B PIN C DIRECTION INPUT ; PORT LAYER metal1 ; RECT 4.600 10.800 5.200 13.400 ; RECT 5.200 10.600 6.000 11.400 ; RECT 4.400 12.600 5.200 13.400 ; END END C PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 -0.600 2.800 4.400 ; RECT -0.400 -0.600 6.800 0.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 3.000 10.800 3.800 18.800 ; RECT 3.400 6.600 6.000 7.400 ; RECT 5.200 1.200 6.000 5.200 ; RECT 5.200 1.200 5.800 7.400 ; RECT 3.400 6.600 4.000 11.400 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 10.800 1.200 20.600 ; RECT -0.400 19.400 6.800 20.600 ; RECT 4.600 14.800 5.400 20.600 ; END END vdd OBS LAYER metal1 ; RECT 0.400 1.200 1.200 5.200 ; RECT 3.600 1.200 4.400 5.200 ; RECT 0.600 5.000 4.200 5.600 ; END END OAI21X1 MACRO OAI22X1 CLASS CORE ; FOREIGN OAI22X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 8.000 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 6.600 1.200 7.400 ; RECT 1.200 6.200 2.000 7.200 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.000 7.800 2.800 9.400 ; END END B PIN C DIRECTION INPUT ; PORT LAYER metal1 ; RECT 6.800 6.600 7.600 8.200 ; END END C PIN D DIRECTION INPUT ; PORT LAYER metal1 ; RECT 5.200 7.800 6.000 9.400 ; END END D PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 -0.600 2.800 4.400 ; RECT -0.400 -0.600 8.400 0.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 3.600 6.600 4.200 18.800 ; RECT 3.600 6.600 6.000 7.200 ; RECT 5.400 2.400 6.000 7.200 ; RECT 5.200 2.400 6.000 5.200 ; RECT 3.000 10.800 5.000 18.800 ; RECT 3.600 6.600 4.400 7.400 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 10.800 1.200 20.600 ; RECT -0.400 19.400 8.400 20.600 ; RECT 6.800 10.800 7.600 20.600 ; END END vdd OBS LAYER metal1 ; RECT 3.600 1.200 7.600 1.800 ; RECT 0.400 1.200 1.200 5.200 ; RECT 3.600 1.200 4.400 5.200 ; RECT 6.800 1.200 7.600 5.200 ; RECT 0.600 5.000 4.200 5.600 ; END END OAI22X1 MACRO OR2X1 CLASS CORE ; FOREIGN OR2X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 6.400 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 3.800 1.200 5.400 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.000 6.600 2.800 7.400 ; RECT 2.200 5.800 3.600 6.600 ; END END B PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 3.200 ; RECT -0.400 -0.600 6.800 0.600 ; RECT 3.600 -0.600 4.400 3.200 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 5.200 1.200 6.000 3.200 ; RECT 5.400 1.200 6.000 14.800 ; RECT 4.600 14.800 5.400 18.800 ; RECT 4.800 14.200 6.000 14.800 ; RECT 5.200 8.600 6.000 9.400 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 3.000 10.800 3.800 20.600 ; RECT -0.400 19.400 6.800 20.600 ; END END vdd OBS LAYER metal1 ; RECT 2.000 1.200 2.800 3.200 ; RECT 2.200 1.200 2.800 4.800 ; RECT 2.200 4.200 4.800 4.800 ; RECT 4.200 4.200 4.800 7.800 ; RECT 3.800 7.200 4.400 10.200 ; RECT 3.800 9.400 4.600 10.200 ; RECT 0.400 9.600 4.600 10.200 ; RECT 0.400 9.600 1.200 18.800 ; END END OR2X1 MACRO OR2X2 CLASS CORE ; FOREIGN OR2X2 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 6.400 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 3.800 1.200 5.400 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.000 6.600 3.000 7.400 ; RECT 2.400 7.400 3.200 8.200 ; END END B PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 3.200 ; RECT -0.400 -0.600 6.800 0.600 ; RECT 3.600 -0.600 4.400 4.800 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 5.200 1.200 6.000 5.200 ; RECT 5.400 1.200 6.000 11.400 ; RECT 4.600 10.800 5.400 18.800 ; RECT 5.200 8.600 6.000 9.400 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 3.000 10.800 3.800 20.600 ; RECT -0.400 19.400 6.800 20.600 ; END END vdd OBS LAYER metal1 ; RECT 2.000 1.200 2.800 3.200 ; RECT 2.200 1.200 2.800 6.000 ; RECT 2.200 5.400 4.600 6.000 ; RECT 3.800 9.000 4.600 9.800 ; RECT 4.000 5.400 4.600 9.800 ; RECT 0.400 9.600 4.400 10.200 ; RECT 0.400 9.600 1.200 18.800 ; END END OR2X2 MACRO TBUFX1 CLASS CORE ; FOREIGN TBUFX1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 8.000 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 6.000 6.600 7.600 7.400 ; END END A PIN EN DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 12.600 2.000 13.400 ; END END EN PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 3.200 ; RECT -0.400 -0.600 8.400 0.600 ; RECT 6.400 -0.600 7.200 5.200 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 3.800 1.200 4.600 5.200 ; RECT 3.800 10.800 4.600 18.800 ; RECT 4.000 1.200 4.600 18.800 ; RECT 3.600 8.600 4.600 9.400 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 14.800 1.200 20.600 ; RECT -0.400 19.400 8.400 20.600 ; RECT 6.400 10.800 7.200 20.600 ; END END vdd OBS LAYER metal1 ; RECT 2.000 1.200 2.800 3.200 ; RECT 2.600 6.600 3.400 7.400 ; RECT 2.600 2.400 3.200 8.000 ; RECT 2.400 7.400 3.000 10.600 ; RECT 2.600 10.000 3.200 15.400 ; RECT 2.000 14.800 2.800 18.800 ; END END TBUFX1 MACRO TBUFX2 CLASS CORE ; FOREIGN TBUFX2 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 11.200 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 9.000 6.600 10.800 7.400 ; END END A PIN EN DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 5.800 1.000 10.200 ; RECT 0.400 5.800 1.400 6.600 ; RECT 0.400 8.600 1.200 10.200 ; END END EN PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 5.200 ; RECT -0.400 -0.600 11.600 0.600 ; RECT 8.400 -0.600 9.200 4.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 5.200 2.400 5.800 17.600 ; RECT 5.200 10.800 6.000 17.600 ; RECT 5.200 8.600 6.000 9.400 ; RECT 5.200 2.400 6.000 5.200 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 10.800 1.200 20.600 ; RECT -0.400 19.400 11.600 20.600 ; RECT 8.400 12.200 9.200 20.600 ; END END vdd OBS LAYER metal1 ; RECT 2.000 1.200 2.800 5.200 ; RECT 2.000 8.200 2.800 9.000 ; RECT 2.000 1.200 2.600 18.800 ; RECT 2.000 10.800 2.800 18.800 ; RECT 6.800 10.800 10.800 11.600 ; RECT 3.600 10.800 4.400 18.800 ; RECT 6.800 10.800 7.600 18.800 ; RECT 3.600 18.200 7.600 18.800 ; RECT 10.000 10.800 10.800 18.800 ; RECT 3.600 1.200 7.600 1.800 ; RECT 10.000 1.200 10.800 4.600 ; RECT 6.800 1.200 7.600 5.800 ; RECT 3.600 1.200 4.400 5.200 ; RECT 10.200 1.200 10.800 5.800 ; RECT 6.800 5.200 10.800 5.800 ; END END TBUFX2 MACRO XOR2X1 CLASS CORE ; FOREIGN XOR2X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 11.200 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 6.600 2.000 7.400 ; RECT 4.000 7.000 4.800 7.800 ; RECT 2.000 7.000 4.800 7.600 ; RECT 0.400 6.800 2.600 7.400 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 9.200 6.600 10.800 7.400 ; END END B PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.200 -0.600 3.000 4.600 ; RECT -0.400 -0.600 11.600 0.600 ; RECT 8.200 -0.600 9.200 4.600 ; RECT 2.000 1.200 3.000 4.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 5.200 8.600 6.000 9.400 ; RECT 4.800 10.800 6.400 18.800 ; RECT 5.800 1.200 6.400 7.400 ; RECT 5.400 6.800 6.000 18.800 ; RECT 4.800 1.200 6.400 4.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 12.200 3.000 18.800 ; RECT -0.400 19.400 11.600 20.600 ; RECT 8.200 12.200 9.200 20.600 ; RECT 2.200 12.200 3.000 20.600 ; END END vdd OBS LAYER metal2 ; RECT 2.200 5.200 3.000 6.000 ; RECT 2.200 5.400 7.800 6.000 ; RECT 3.600 5.400 4.400 6.200 ; RECT 7.000 5.400 7.800 6.200 ; RECT 2.200 5.200 2.800 11.600 ; RECT 2.200 10.800 3.000 11.600 ; RECT 8.400 5.200 9.200 6.000 ; RECT 3.600 6.800 9.200 7.400 ; RECT 3.600 6.800 4.200 9.600 ; RECT 3.400 8.800 4.200 9.600 ; RECT 8.600 5.200 9.200 11.600 ; RECT 8.400 10.800 9.200 11.600 ; LAYER metal1 ; RECT 0.400 10.800 3.000 11.400 ; RECT 2.200 10.800 3.000 11.600 ; RECT 0.400 10.800 1.200 18.800 ; RECT 0.400 1.200 1.200 5.800 ; RECT 0.400 5.200 3.000 5.800 ; RECT 2.200 5.200 3.000 6.000 ; RECT 2.600 8.600 3.400 9.400 ; RECT 3.400 8.800 4.200 9.600 ; RECT 3.600 5.400 5.200 6.200 ; RECT 7.000 5.400 7.800 6.200 ; RECT 7.200 5.400 7.800 7.400 ; RECT 7.200 6.600 8.000 7.400 ; RECT 8.400 10.800 10.800 11.400 ; RECT 8.400 10.800 9.200 11.600 ; RECT 10.000 10.800 10.800 18.800 ; RECT 10.000 1.200 10.800 5.800 ; RECT 8.400 5.200 10.800 5.800 ; RECT 8.400 5.200 9.200 6.000 ; LAYER via1 ; RECT 2.400 11.000 2.800 11.400 ; RECT 2.400 5.400 2.800 5.800 ; RECT 3.600 9.000 4.000 9.400 ; RECT 3.800 5.600 4.200 6.000 ; RECT 7.200 5.600 7.600 6.000 ; RECT 8.600 11.000 9.000 11.400 ; RECT 8.600 5.400 9.000 5.800 ; END END XOR2X1 MACRO MUX2X1 CLASS CORE ; FOREIGN MUX2X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 9.600 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 6.800 8.600 7.600 10.200 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.000 7.800 2.800 9.400 ; END END B PIN S DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 7.800 1.200 9.400 ; END END S PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 -0.600 2.800 5.600 ; RECT -0.400 -0.600 10.000 0.600 ; RECT 7.200 -0.600 8.000 6.000 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 4.600 2.000 5.400 5.600 ; RECT 5.600 6.600 7.600 7.400 ; RECT 4.600 11.200 6.200 11.800 ; RECT 5.600 5.000 6.200 11.800 ; RECT 5.400 5.000 6.200 6.000 ; RECT 4.600 11.200 5.400 18.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 11.200 2.800 20.600 ; RECT -0.400 19.400 10.000 20.600 ; RECT 7.200 10.800 8.000 20.600 ; END END vdd OBS LAYER metal1 ; RECT 0.400 2.000 1.200 4.000 ; RECT 0.400 2.000 1.000 6.800 ; RECT 0.400 6.200 4.600 6.800 ; RECT 3.600 6.200 4.600 8.000 ; RECT 3.600 7.200 5.000 8.000 ; RECT 3.600 6.200 4.200 10.600 ; RECT 0.400 10.000 4.200 10.600 ; RECT 0.400 10.000 1.000 18.000 ; RECT 0.400 14.000 1.200 18.000 ; END END MUX2X1 MACRO XNOR2X1 CLASS CORE ; FOREIGN XNOR2X1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 11.200 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal2 ; RECT 3.600 5.400 4.400 6.200 ; RECT 7.000 5.400 7.800 6.200 ; RECT 3.600 5.400 7.800 6.000 ; LAYER via1 ; RECT 3.800 5.600 4.200 6.000 ; RECT 7.200 5.600 7.600 6.000 ; LAYER metal1 ; RECT 0.400 6.600 2.000 7.400 ; RECT 7.200 6.600 8.000 7.400 ; RECT 7.200 5.400 7.800 7.400 ; RECT 7.000 5.400 7.800 6.200 ; RECT 3.600 5.400 5.200 6.200 ; RECT 0.400 6.600 3.800 7.200 ; RECT 3.200 5.600 3.800 7.200 ; END END A PIN B DIRECTION INPUT ; PORT LAYER metal1 ; RECT 9.200 6.600 10.800 7.400 ; END END B PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.200 -0.600 3.000 4.600 ; RECT -0.400 -0.600 11.600 0.600 ; RECT 8.200 -0.600 9.200 4.600 ; RECT 2.000 1.200 3.000 4.600 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 4.800 1.200 6.400 4.800 ; RECT 6.200 8.600 7.600 9.400 ; RECT 6.200 8.200 6.800 11.400 ; RECT 4.800 10.800 6.400 18.800 ; RECT 5.800 1.200 6.400 8.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 12.200 3.000 18.800 ; RECT -0.400 19.400 11.600 20.600 ; RECT 8.200 12.200 9.200 20.600 ; RECT 2.200 12.200 3.000 20.600 ; END END vdd OBS LAYER metal2 ; RECT 1.800 5.200 2.600 6.000 ; RECT 1.800 5.200 2.400 11.600 ; RECT 1.800 10.800 2.600 11.600 ; RECT 8.400 5.200 9.200 6.000 ; RECT 4.400 6.800 9.200 7.400 ; RECT 4.400 6.800 5.200 7.600 ; RECT 8.600 5.200 9.200 11.600 ; RECT 8.400 10.800 9.200 11.600 ; LAYER metal1 ; RECT 0.400 1.200 1.200 5.800 ; RECT 0.400 5.200 2.600 5.800 ; RECT 1.800 5.200 2.600 6.000 ; RECT 4.400 6.800 5.200 7.600 ; RECT 4.400 6.800 5.000 8.800 ; RECT 2.400 8.200 5.000 8.800 ; RECT 2.400 8.200 3.200 9.000 ; RECT 4.600 9.400 5.400 10.200 ; RECT 2.000 9.600 5.400 10.200 ; RECT 0.400 10.800 2.600 11.400 ; RECT 2.000 9.600 2.600 11.600 ; RECT 1.800 10.800 2.600 11.600 ; RECT 0.400 10.800 1.200 18.800 ; RECT 8.400 10.800 10.800 11.400 ; RECT 8.400 10.800 9.200 11.600 ; RECT 10.000 10.800 10.800 18.800 ; RECT 10.000 1.200 10.800 5.800 ; RECT 8.400 5.200 10.800 5.800 ; RECT 8.400 5.200 9.200 6.000 ; LAYER via1 ; RECT 2.000 11.000 2.400 11.400 ; RECT 2.000 5.400 2.400 5.800 ; RECT 4.600 7.000 5.000 7.400 ; RECT 8.600 11.000 9.000 11.400 ; RECT 8.600 5.400 9.000 5.800 ; END END XNOR2X1 MACRO LATCH CLASS CORE ; FOREIGN LATCH 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 11.200 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN Q DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 7.400 7.600 10.800 8.400 ; RECT 10.000 1.200 10.800 18.800 ; END END Q PIN CLK DIRECTION INPUT ; PORT LAYER metal1 ; RECT 1.200 6.600 2.800 7.400 ; RECT 5.800 6.600 6.600 8.200 ; RECT 1.200 6.600 6.600 7.200 ; RECT 4.400 4.600 5.200 7.200 ; END END CLK PIN D DIRECTION INPUT ; PORT LAYER metal1 ; RECT 2.600 9.400 4.400 10.200 ; RECT 3.600 9.400 4.400 11.400 ; END END D PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 -0.600 2.800 5.200 ; RECT -0.400 -0.600 11.600 0.600 ; RECT 8.400 -0.600 9.200 5.200 ; END END gnd PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 2.000 10.800 2.800 20.600 ; RECT -0.400 19.400 11.600 20.600 ; RECT 8.400 10.800 9.200 20.600 ; END END vdd OBS LAYER metal2 ; RECT 0.400 5.200 1.200 10.800 ; RECT 5.200 3.200 6.000 14.800 ; LAYER metal1 ; RECT 0.400 9.800 1.200 18.800 ; RECT 0.400 1.200 1.200 6.000 ; RECT 0.400 8.000 5.000 8.600 ; RECT 0.400 8.000 1.200 8.800 ; RECT 4.200 8.000 5.000 8.800 ; RECT 5.200 14.000 6.000 18.800 ; RECT 5.000 14.800 6.200 18.800 ; RECT 5.000 1.200 6.200 3.200 ; RECT 5.200 1.200 6.000 4.000 ; RECT 5.200 9.400 9.400 10.200 ; LAYER via1 ; RECT 0.600 10.200 1.000 10.600 ; RECT 0.600 8.200 1.000 8.600 ; RECT 0.600 5.400 1.000 5.800 ; RECT 5.400 14.200 5.800 14.600 ; RECT 5.400 9.600 5.800 10.000 ; RECT 5.400 3.400 5.800 3.800 ; END END LATCH MACRO DFFSR CLASS CORE ; FOREIGN DFFSR 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 35.200 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN Q DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 32.400 1.200 33.200 5.800 ; RECT 32.600 5.000 33.400 11.000 ; RECT 32.400 10.200 33.200 18.800 ; END END Q PIN CLK DIRECTION INPUT ; PORT LAYER metal1 ; RECT 16.400 4.600 18.000 5.400 ; END END CLK PIN R DIRECTION INPUT ; PORT LAYER metal1 ; RECT 1.800 8.800 2.600 9.600 ; RECT 1.800 9.000 25.200 9.600 ; RECT 24.400 8.400 25.200 9.600 ; RECT 6.800 8.600 7.600 9.600 ; END END R PIN S DIRECTION INPUT ; PORT LAYER metal1 ; RECT 3.600 10.200 4.400 11.400 ; RECT 3.600 10.200 30.600 10.800 ; RECT 29.800 10.000 30.600 10.800 ; RECT 7.000 10.200 7.800 11.000 ; END END S PIN D DIRECTION INPUT ; PORT LAYER metal1 ; RECT 13.200 5.800 14.000 7.400 ; END END D PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 3.600 -0.600 4.400 5.200 ; RECT -0.400 -0.600 35.600 0.600 ; RECT 34.000 -0.600 34.800 3.200 ; RECT 27.600 -0.600 28.400 5.200 ; RECT 16.400 -0.600 17.200 3.200 ; RECT 13.200 -0.600 14.000 3.200 ; END END gnd PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 14.800 1.200 20.600 ; RECT -0.400 19.400 35.600 20.600 ; RECT 34.000 14.800 34.800 20.600 ; RECT 30.800 14.800 31.600 20.600 ; RECT 27.600 14.800 28.400 20.600 ; RECT 24.400 14.800 25.200 20.600 ; RECT 16.400 14.800 17.200 20.600 ; RECT 13.200 14.800 14.000 20.600 ; RECT 6.800 14.800 7.600 20.600 ; RECT 3.600 14.800 4.400 20.600 ; END END vdd OBS LAYER metal2 ; RECT 8.400 3.200 9.200 16.800 ; RECT 10.000 3.200 10.800 16.800 ; RECT 11.600 3.200 12.400 14.800 ; RECT 14.800 3.200 15.600 14.800 ; RECT 18.000 3.200 18.800 14.800 ; RECT 19.600 3.200 20.400 16.800 ; RECT 21.200 3.200 22.000 16.800 ; RECT 22.800 3.200 23.600 16.800 ; LAYER metal1 ; RECT 6.800 1.200 7.600 5.200 ; RECT 5.000 4.400 7.600 5.200 ; RECT 5.000 4.400 5.800 6.600 ; RECT 2.800 5.800 5.800 6.600 ; RECT 8.400 16.000 9.200 18.800 ; RECT 0.400 7.200 9.200 8.000 ; RECT 0.400 1.200 1.200 14.200 ; RECT 0.400 13.600 2.400 14.200 ; RECT 1.800 13.600 2.400 15.400 ; RECT 2.000 14.800 2.800 18.800 ; RECT 8.400 1.200 9.200 4.000 ; RECT 10.000 16.000 10.800 18.800 ; RECT 5.400 11.600 10.800 12.200 ; RECT 10.000 11.400 10.800 12.200 ; RECT 4.600 12.000 6.000 12.800 ; RECT 10.000 1.200 10.800 4.000 ; RECT 11.600 14.000 12.400 18.800 ; RECT 11.600 1.200 12.400 4.000 ; RECT 14.800 14.000 15.600 18.800 ; RECT 13.000 12.600 15.600 13.400 ; RECT 11.000 4.600 15.600 5.200 ; RECT 14.800 4.600 15.600 5.400 ; RECT 11.000 4.600 11.800 8.400 ; RECT 9.800 7.600 11.800 8.400 ; RECT 14.800 1.200 15.600 4.000 ; RECT 18.000 12.600 18.800 18.800 ; RECT 15.600 7.600 18.800 8.400 ; RECT 18.000 1.200 18.800 4.000 ; RECT 14.800 6.000 15.600 6.800 ; RECT 14.800 6.200 19.200 6.800 ; RECT 18.400 6.200 19.200 7.000 ; RECT 19.600 16.000 20.400 18.800 ; RECT 11.800 11.400 20.400 12.000 ; RECT 19.600 11.400 20.400 12.200 ; RECT 2.000 12.200 3.600 13.000 ; RECT 3.000 12.200 3.600 14.200 ; RECT 6.600 12.800 12.400 13.400 ; RECT 11.800 11.400 12.400 13.400 ; RECT 3.000 13.400 7.200 14.200 ; RECT 5.200 13.400 6.000 18.800 ; RECT 19.600 1.200 20.400 4.000 ; RECT 21.200 16.000 22.000 18.800 ; RECT 21.000 4.600 22.000 5.400 ; RECT 21.200 4.600 22.000 8.200 ; RECT 21.200 1.200 22.000 4.000 ; RECT 22.800 16.000 23.600 18.800 ; RECT 22.800 1.200 23.600 4.000 ; RECT 21.200 13.400 25.400 14.200 ; RECT 26.000 12.600 28.600 13.400 ; RECT 26.000 12.600 26.800 18.800 ; RECT 24.400 1.200 25.200 5.200 ; RECT 24.400 4.400 26.800 5.200 ; RECT 26.000 4.400 26.800 6.400 ; RECT 26.000 5.800 27.800 6.400 ; RECT 27.000 5.800 27.800 8.400 ; RECT 27.000 7.600 30.800 8.400 ; RECT 30.800 1.200 31.600 7.000 ; RECT 31.400 6.400 32.000 9.600 ; RECT 22.800 11.400 31.800 12.000 ; RECT 22.800 11.400 23.600 12.200 ; RECT 31.200 9.000 31.800 14.200 ; RECT 29.200 13.600 31.800 14.200 ; RECT 29.200 13.600 30.000 18.800 ; LAYER via1 ; RECT 8.600 16.200 9.000 16.600 ; RECT 8.600 7.400 9.000 7.800 ; RECT 8.600 3.400 9.000 3.800 ; RECT 10.200 16.200 10.600 16.600 ; RECT 10.200 11.600 10.600 12.000 ; RECT 10.200 3.400 10.600 3.800 ; RECT 11.800 14.200 12.200 14.600 ; RECT 11.800 3.400 12.200 3.800 ; RECT 15.000 14.200 15.400 14.600 ; RECT 15.000 12.800 15.400 13.200 ; RECT 15.000 6.200 15.400 6.600 ; RECT 15.000 3.400 15.400 3.800 ; RECT 18.200 14.200 18.600 14.600 ; RECT 18.200 7.800 18.600 8.200 ; RECT 18.200 3.400 18.600 3.800 ; RECT 19.800 16.200 20.200 16.600 ; RECT 19.800 11.600 20.200 12.000 ; RECT 19.800 3.400 20.200 3.800 ; RECT 21.400 16.200 21.800 16.600 ; RECT 21.400 13.600 21.800 14.000 ; RECT 21.400 3.400 21.800 3.800 ; RECT 23.000 16.200 23.400 16.600 ; RECT 23.000 11.600 23.400 12.000 ; RECT 23.000 3.400 23.400 3.800 ; END END DFFSR MACRO CLKBUF1 CLASS CORE ; FOREIGN CLKBUF1 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 14.400 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 6.600 1.200 8.000 ; RECT 0.400 7.200 2.200 8.000 ; END END A PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 5.200 ; RECT -0.400 -0.600 14.800 0.600 ; RECT 13.200 -0.600 14.000 5.200 ; RECT 10.000 -0.600 10.800 5.200 ; RECT 6.800 -0.600 7.600 5.200 ; RECT 3.600 -0.600 4.400 5.200 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 11.600 1.200 12.400 6.600 ; RECT 11.600 9.400 14.000 10.200 ; RECT 13.200 5.800 14.000 10.200 ; RECT 11.600 5.800 14.000 6.600 ; RECT 11.600 9.400 12.400 18.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 10.800 1.200 20.600 ; RECT -0.400 19.400 14.800 20.600 ; RECT 13.200 10.800 14.000 20.600 ; RECT 10.000 10.800 10.800 20.600 ; RECT 6.800 10.800 7.600 20.600 ; RECT 3.600 10.800 4.400 20.600 ; END END vdd OBS LAYER metal1 ; RECT 2.000 1.200 2.800 6.600 ; RECT 2.000 5.800 3.800 6.600 ; RECT 3.000 7.200 5.600 8.000 ; RECT 3.000 5.800 3.800 10.200 ; RECT 2.000 9.400 3.800 10.200 ; RECT 2.000 9.400 2.800 18.800 ; RECT 5.200 1.200 6.000 6.600 ; RECT 5.200 5.800 7.400 6.600 ; RECT 6.600 7.200 9.000 8.000 ; RECT 6.600 5.800 7.400 10.200 ; RECT 5.200 9.400 7.400 10.200 ; RECT 5.200 9.400 6.000 18.800 ; RECT 8.400 1.200 9.200 6.600 ; RECT 8.400 5.800 10.600 6.600 ; RECT 9.800 7.200 12.400 8.000 ; RECT 9.800 5.800 10.600 10.200 ; RECT 8.400 9.400 10.600 10.200 ; RECT 8.400 9.400 9.200 18.800 ; END END CLKBUF1 MACRO CLKBUF2 CLASS CORE ; FOREIGN CLKBUF2 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 20.800 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 6.600 1.200 8.000 ; RECT 0.400 7.200 2.200 8.000 ; END END A PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 5.200 ; RECT -0.400 -0.600 21.200 0.600 ; RECT 19.600 -0.600 20.400 5.200 ; RECT 16.400 -0.600 17.200 5.200 ; RECT 13.200 -0.600 14.000 5.200 ; RECT 10.000 -0.600 10.800 5.200 ; RECT 6.800 -0.600 7.600 5.200 ; RECT 3.600 -0.600 4.400 5.200 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 18.000 1.200 18.800 6.600 ; RECT 18.000 9.400 20.400 10.200 ; RECT 19.600 5.800 20.400 10.200 ; RECT 18.000 5.800 20.400 6.600 ; RECT 18.000 9.400 18.800 18.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 10.800 1.200 20.600 ; RECT -0.400 19.400 21.200 20.600 ; RECT 19.600 10.800 20.400 20.600 ; RECT 16.400 10.800 17.200 20.600 ; RECT 13.200 10.800 14.000 20.600 ; RECT 10.000 10.800 10.800 20.600 ; RECT 6.800 10.800 7.600 20.600 ; RECT 3.600 10.800 4.400 20.600 ; END END vdd OBS LAYER metal1 ; RECT 2.000 1.200 2.800 6.600 ; RECT 2.000 5.800 3.800 6.600 ; RECT 3.000 7.200 5.600 8.000 ; RECT 3.000 5.800 3.800 10.200 ; RECT 2.000 9.400 3.800 10.200 ; RECT 2.000 9.400 2.800 18.800 ; RECT 5.200 1.200 6.000 6.600 ; RECT 5.200 5.800 7.400 6.600 ; RECT 6.600 7.200 9.000 8.000 ; RECT 6.600 5.800 7.400 10.200 ; RECT 5.200 9.400 7.400 10.200 ; RECT 5.200 9.400 6.000 18.800 ; RECT 8.400 1.200 9.200 6.600 ; RECT 8.400 5.800 10.600 6.600 ; RECT 9.800 7.200 12.400 8.000 ; RECT 9.800 5.800 10.600 10.200 ; RECT 8.400 9.400 10.600 10.200 ; RECT 8.400 9.400 9.200 18.800 ; RECT 11.600 1.200 12.400 6.600 ; RECT 11.600 5.800 14.000 6.600 ; RECT 13.200 7.200 15.000 8.000 ; RECT 13.200 5.800 14.000 10.200 ; RECT 11.600 9.400 14.000 10.200 ; RECT 11.600 9.400 12.400 18.800 ; RECT 14.800 1.200 15.600 6.600 ; RECT 14.800 5.800 16.600 6.600 ; RECT 15.800 7.200 18.400 8.000 ; RECT 15.800 5.800 16.600 10.200 ; RECT 14.800 9.400 16.600 10.200 ; RECT 14.800 9.400 15.600 18.800 ; END END CLKBUF2 MACRO CLKBUF3 CLASS CORE ; FOREIGN CLKBUF3 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 27.200 BY 20.000 ; SYMMETRY X Y ; SITE core ; PIN A DIRECTION INPUT ; PORT LAYER metal1 ; RECT 0.400 6.600 1.200 8.000 ; RECT 0.400 7.200 2.200 8.000 ; END END A PIN gnd DIRECTION INOUT ; USE GROUND ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 -0.600 1.200 5.200 ; RECT -0.400 -0.600 27.600 0.600 ; RECT 26.000 -0.600 26.800 5.200 ; RECT 22.800 -0.600 23.600 5.200 ; RECT 19.600 -0.600 20.400 5.200 ; RECT 16.400 -0.600 17.200 5.200 ; RECT 13.200 -0.600 14.000 5.200 ; RECT 10.000 -0.600 10.800 5.200 ; RECT 6.800 -0.600 7.600 5.200 ; RECT 3.600 -0.600 4.400 5.200 ; END END gnd PIN Y DIRECTION OUTPUT ; PORT LAYER metal1 ; RECT 24.400 1.200 25.200 6.600 ; RECT 24.400 9.400 26.800 10.200 ; RECT 26.000 5.800 26.800 10.200 ; RECT 24.400 5.800 26.800 6.600 ; RECT 24.400 9.400 25.200 18.800 ; END END Y PIN vdd DIRECTION INOUT ; USE POWER ; SHAPE ABUTMENT ; PORT LAYER metal1 ; RECT 0.400 10.800 1.200 20.600 ; RECT -0.400 19.400 27.600 20.600 ; RECT 26.000 10.800 26.800 20.600 ; RECT 22.800 10.800 23.600 20.600 ; RECT 19.600 10.800 20.400 20.600 ; RECT 16.400 10.800 17.200 20.600 ; RECT 13.200 10.800 14.000 20.600 ; RECT 10.000 10.800 10.800 20.600 ; RECT 6.800 10.800 7.600 20.600 ; RECT 3.600 10.800 4.400 20.600 ; END END vdd OBS LAYER metal1 ; RECT 2.000 1.200 2.800 6.600 ; RECT 2.000 5.800 3.800 6.600 ; RECT 3.000 7.200 5.600 8.000 ; RECT 3.000 5.800 3.800 10.200 ; RECT 2.000 9.400 3.800 10.200 ; RECT 2.000 9.400 2.800 18.800 ; RECT 5.200 1.200 6.000 6.600 ; RECT 5.200 5.800 7.400 6.600 ; RECT 6.600 7.200 9.000 8.000 ; RECT 6.600 5.800 7.400 10.200 ; RECT 5.200 9.400 7.400 10.200 ; RECT 5.200 9.400 6.000 18.800 ; RECT 8.400 1.200 9.200 6.600 ; RECT 8.400 5.800 10.600 6.600 ; RECT 9.800 7.200 12.400 8.000 ; RECT 9.800 5.800 10.600 10.200 ; RECT 8.400 9.400 10.600 10.200 ; RECT 8.400 9.400 9.200 18.800 ; RECT 11.600 1.200 12.400 6.600 ; RECT 11.600 5.800 14.000 6.600 ; RECT 13.200 7.200 15.000 8.000 ; RECT 13.200 5.800 14.000 10.200 ; RECT 11.600 9.400 14.000 10.200 ; RECT 11.600 9.400 12.400 18.800 ; RECT 14.800 1.200 15.600 6.600 ; RECT 14.800 5.800 16.600 6.600 ; RECT 15.800 7.200 18.400 8.000 ; RECT 15.800 5.800 16.600 10.200 ; RECT 14.800 9.400 16.600 10.200 ; RECT 14.800 9.400 15.600 18.800 ; RECT 18.000 1.200 18.800 6.600 ; RECT 18.000 5.800 20.200 6.600 ; RECT 19.400 7.200 21.800 8.000 ; RECT 19.400 5.800 20.200 10.200 ; RECT 18.000 9.400 20.200 10.200 ; RECT 18.000 9.400 18.800 18.800 ; RECT 21.200 1.200 22.000 6.600 ; RECT 21.200 5.800 23.400 6.600 ; RECT 22.600 7.200 25.200 8.000 ; RECT 22.600 5.800 23.400 10.200 ; RECT 21.200 9.400 23.400 10.200 ; RECT 21.200 9.400 22.000 18.800 ; END END CLKBUF3 MACRO PADFC CLASS ENDCAP TOPLEFT ; FOREIGN PADFC 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 300.000 BY 300.000 ; SYMMETRY X Y R90 ; SITE corner ; OBS LAYER metal4 ; RECT 0.600 0.600 299.400 299.400 ; LAYER metal3 ; RECT 0.600 0.600 299.400 299.400 ; LAYER metal2 ; RECT 98.000 0.000 170.400 299.400 ; RECT 174.800 0.000 195.800 299.400 ; RECT 202.200 0.000 223.200 299.400 ; RECT 227.600 0.000 300.000 72.400 ; RECT 0.600 76.800 300.000 97.800 ; RECT 0.600 104.000 300.000 125.200 ; RECT 0.600 129.600 300.000 202.000 ; RECT 0.600 0.600 299.400 299.400 ; LAYER metal1 ; RECT 98.000 0.000 195.800 299.400 ; RECT 202.200 0.000 300.000 97.800 ; RECT 0.600 104.000 300.000 202.000 ; RECT 0.600 0.600 299.400 299.400 ; END END PADFC MACRO PADGND CLASS PAD ; FOREIGN PADGND 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 90.000 BY 300.000 ; SYMMETRY R90 ; SITE IO ; PIN YPAD DIRECTION OUTPUT ; PORT LAYER metal4 ; RECT 37.400 254.800 51.200 269.800 ; END END YPAD PIN gnd DIRECTION INOUT ; USE GROUND ; PORT CLASS CORE ; LAYER metal1 ; RECT 34.800 0.000 54.800 0.800 ; END END gnd OBS LAYER metal4 ; RECT 0.600 0.600 89.400 253.000 ; RECT 0.600 271.600 89.400 299.000 ; RECT 0.600 0.600 35.600 299.400 ; RECT 53.000 0.600 89.400 299.400 ; LAYER metal3 ; RECT 0.600 0.600 89.400 299.400 ; LAYER metal2 ; RECT 0.000 0.000 90.000 72.400 ; RECT 0.600 76.600 89.600 97.800 ; RECT 0.000 76.800 90.000 97.800 ; RECT 0.000 104.200 90.000 125.200 ; RECT 0.000 129.600 90.000 202.000 ; RECT 0.600 0.000 89.400 299.400 ; RECT 6.000 0.000 84.000 300.000 ; LAYER metal1 ; RECT 0.000 0.000 34.200 97.800 ; RECT 55.600 0.000 90.000 97.800 ; RECT 0.000 104.200 90.000 202.000 ; RECT 0.600 1.800 89.400 299.400 ; RECT 6.000 1.800 84.000 300.000 ; END END PADGND MACRO PADVDD CLASS PAD ; FOREIGN PADVDD 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 90.000 BY 300.000 ; SYMMETRY R90 ; SITE IO ; PIN YPAD DIRECTION OUTPUT ; PORT LAYER metal4 ; RECT 42.200 266.000 44.400 268.400 ; END END YPAD PIN vdd DIRECTION INOUT ; USE POWER ; PORT CLASS CORE ; LAYER metal1 ; RECT 35.400 0.000 54.600 0.800 ; END END vdd OBS LAYER metal4 ; RECT 0.600 0.600 89.400 264.200 ; RECT 0.600 270.200 89.400 299.000 ; RECT 0.600 0.600 40.400 299.400 ; RECT 46.200 0.600 89.400 299.400 ; LAYER metal3 ; RECT 0.600 0.600 89.400 299.400 ; LAYER metal2 ; RECT 0.000 0.000 34.400 72.400 ; RECT 35.400 0.000 54.600 300.000 ; RECT 55.600 0.000 90.000 72.400 ; RECT 0.000 76.800 90.000 97.800 ; RECT 0.000 104.200 90.000 125.200 ; RECT 0.000 129.600 90.000 202.000 ; RECT 0.600 1.800 89.400 299.400 ; RECT 6.000 1.800 84.000 300.000 ; LAYER metal1 ; RECT 0.000 0.000 34.400 97.800 ; RECT 55.600 0.000 90.000 97.800 ; RECT 0.000 104.200 90.000 202.000 ; RECT 0.600 1.800 89.400 299.400 ; RECT 6.000 1.800 84.000 300.000 ; END END PADVDD MACRO PADINC CLASS PAD ; FOREIGN PADINC 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 90.000 BY 300.000 ; SYMMETRY R90 ; SITE IO ; PIN YPAD DIRECTION OUTPUT ; PORT LAYER metal4 ; RECT 42.200 266.000 44.400 268.400 ; END END YPAD PIN DI DIRECTION OUTPUT ; PORT LAYER metal2 ; RECT 82.200 -0.400 83.000 0.400 ; RECT 81.600 0.000 83.400 0.400 ; END END DI OBS LAYER metal4 ; RECT 0.600 0.600 89.400 264.200 ; RECT 0.600 270.200 89.400 299.000 ; RECT 0.600 0.600 40.400 299.400 ; RECT 46.200 0.600 89.400 299.400 ; LAYER metal3 ; RECT 0.600 0.600 80.600 299.400 ; RECT 84.400 0.600 89.400 299.400 ; RECT 0.600 1.400 89.400 299.400 ; LAYER metal2 ; RECT 0.000 0.000 34.400 72.400 ; RECT 35.400 0.000 54.600 300.000 ; RECT 55.600 0.000 78.200 300.000 ; RECT 79.000 0.000 80.800 300.000 ; RECT 0.000 0.600 80.800 72.400 ; RECT 84.200 0.000 90.000 72.400 ; RECT 0.000 76.800 90.000 97.800 ; RECT 0.000 104.200 90.000 125.200 ; RECT 0.000 129.600 90.000 202.000 ; RECT 0.600 1.400 89.400 299.400 ; RECT 6.000 1.400 84.000 300.000 ; LAYER metal1 ; RECT 0.000 0.000 90.000 97.800 ; RECT 0.000 104.200 90.000 202.000 ; RECT 0.600 0.000 89.400 299.400 ; RECT 6.000 0.000 84.000 300.000 ; END END PADINC MACRO PADINOUT CLASS PAD ; FOREIGN PADINOUT 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 90.000 BY 300.000 ; SYMMETRY R90 ; SITE IO ; PIN YPAD DIRECTION OUTPUT ; PORT LAYER metal4 ; RECT 42.200 266.000 44.400 268.400 ; END END YPAD PIN DO DIRECTION INPUT ; PORT LAYER metal2 ; RECT 8.200 -0.400 9.000 0.400 ; RECT 7.600 0.000 9.400 0.400 ; END END DO PIN DI DIRECTION OUTPUT ; PORT LAYER metal2 ; RECT 82.200 -0.400 83.000 0.400 ; RECT 81.600 0.000 83.400 0.400 ; END END DI PIN OEN DIRECTION INPUT ; PORT LAYER metal2 ; RECT 2.600 -0.400 3.400 0.400 ; RECT 2.200 0.000 4.000 0.400 ; END END OEN OBS LAYER metal4 ; RECT 0.600 0.600 89.400 264.200 ; RECT 0.600 270.200 89.400 299.000 ; RECT 0.600 0.600 40.400 299.400 ; RECT 46.200 0.600 89.400 299.400 ; LAYER metal3 ; RECT 0.600 0.600 1.200 299.400 ; RECT 5.000 0.600 6.600 299.400 ; RECT 10.400 0.600 80.600 299.400 ; RECT 84.400 0.600 89.400 299.400 ; RECT 0.600 1.400 89.400 299.400 ; LAYER metal2 ; RECT 10.200 0.000 34.400 300.000 ; RECT 35.400 0.000 54.600 300.000 ; RECT 55.600 0.000 78.200 300.000 ; RECT 0.000 0.000 1.400 72.400 ; RECT 4.800 0.000 6.800 299.400 ; RECT 79.000 0.000 80.800 300.000 ; RECT 10.200 0.600 80.800 300.000 ; RECT 84.200 0.000 90.000 72.400 ; RECT 0.000 76.800 90.000 97.800 ; RECT 0.000 104.200 90.000 125.200 ; RECT 0.000 129.600 90.000 202.000 ; RECT 0.600 1.400 89.400 299.400 ; RECT 6.000 1.400 84.000 300.000 ; LAYER metal1 ; RECT 0.000 0.000 90.000 97.800 ; RECT 0.000 104.200 90.000 202.000 ; RECT 0.600 0.000 89.400 299.400 ; RECT 6.000 0.000 84.000 300.000 ; END END PADINOUT MACRO PADNC CLASS PAD ; FOREIGN PADNC 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 90.000 BY 300.000 ; SYMMETRY R90 ; SITE IO ; OBS LAYER metal4 ; RECT 0.600 0.600 89.400 299.400 ; LAYER metal3 ; RECT 0.600 0.600 89.400 299.400 ; LAYER metal2 ; RECT 0.000 0.000 90.000 72.400 ; RECT 0.000 76.800 90.000 97.800 ; RECT 0.000 104.200 90.000 125.200 ; RECT 0.000 129.600 90.000 202.000 ; RECT 0.600 0.000 89.400 299.400 ; LAYER metal1 ; RECT 0.000 0.000 90.000 97.800 ; RECT 0.000 104.200 90.000 202.000 ; RECT 0.600 0.000 89.400 299.400 ; END END PADNC MACRO PADOUT CLASS PAD ; FOREIGN PADOUT 0.000 0.000 ; ORIGIN 0.000 0.000 ; SIZE 90.000 BY 300.000 ; SYMMETRY R90 ; SITE IO ; PIN YPAD DIRECTION OUTPUT ; PORT LAYER metal4 ; RECT 42.200 266.000 44.400 268.400 ; END END YPAD PIN DO DIRECTION INPUT ; PORT LAYER metal2 ; RECT 8.200 -0.400 9.000 0.400 ; RECT 7.600 0.000 9.400 0.400 ; END END DO OBS LAYER metal4 ; RECT 0.600 0.600 89.400 264.200 ; RECT 0.600 270.200 89.400 299.000 ; RECT 0.600 0.600 40.400 299.400 ; RECT 46.200 0.600 89.400 299.400 ; LAYER metal3 ; RECT 0.600 0.600 6.600 299.400 ; RECT 10.400 0.600 89.400 299.400 ; RECT 0.600 1.400 89.400 299.400 ; LAYER metal2 ; RECT 0.000 0.000 1.400 72.400 ; RECT 2.200 0.000 4.000 299.400 ; RECT 4.800 0.000 6.800 299.400 ; RECT 10.200 0.000 34.400 300.000 ; RECT 35.400 0.000 54.600 300.000 ; RECT 55.600 0.000 78.200 300.000 ; RECT 79.000 0.000 80.800 300.000 ; RECT 81.600 0.000 83.400 300.000 ; RECT 0.000 0.600 6.800 72.400 ; RECT 10.200 0.600 90.000 72.400 ; RECT 84.200 0.000 90.000 72.400 ; RECT 0.000 76.800 90.000 97.800 ; RECT 0.000 104.200 90.000 125.200 ; RECT 0.000 129.600 90.000 202.000 ; RECT 0.600 1.400 89.400 299.400 ; RECT 6.000 1.400 84.000 300.000 ; LAYER metal1 ; RECT 0.000 0.000 90.000 97.800 ; RECT 0.000 104.200 90.000 202.000 ; RECT 0.600 0.000 89.400 299.400 ; RECT 6.000 0.000 84.000 300.000 ; END END PADOUT END LIBRARY qrouter-1.3.33/qrouter.c0000664000175000001440000033744112625401740013676 0ustar timusers/*--------------------------------------------------------------*/ /* qrouter.c -- general purpose autorouter */ /* Reads LEF libraries and DEF netlists, and generates an */ /* annotated DEF netlist as output. */ /*--------------------------------------------------------------*/ /* Written by Tim Edwards, June 2011, based on code by Steve */ /* Beccue, 2003 */ /*--------------------------------------------------------------*/ #include #include #include #include #include #include "qrouter.h" #include "qconfig.h" #include "node.h" #include "maze.h" #include "lef.h" int Pathon = -1; int TotalRoutes = 0; NET *Nlnets; // list of nets in the design NET CurNet; // current net to route, used by 2nd stage STRING DontRoute; // a list of nets not to route (e.g., power) STRING CriticalNet; // list of critical nets to route first GATE GateInfo; // standard cell macro information GATE PinMacro; // macro definition for a pin GATE Nlgates; // gate instance information NETLIST FailedNets; // list of nets that failed to route u_char *RMask; // mask out best area to route u_int *Obs[MAX_LAYERS]; // net obstructions in layer PROUTE *Obs2[MAX_LAYERS]; // used for pt->pt routes on layer float *Stub[MAX_LAYERS]; // used for stub routing to pins float *Obsinfo[MAX_LAYERS]; // temporary array used for detailed obstruction info NODE *Nodeloc[MAX_LAYERS]; // nodes are here. . . NODE *Nodesav[MAX_LAYERS]; // . . . and here (but not to be altered) DSEG UserObs; // user-defined obstruction layers u_char needblock[MAX_LAYERS]; char *vddnet = NULL; char *gndnet = NULL; int Numnets = 0; int Pinlayers = 0; u_char Verbose = 3; // Default verbose level u_char keepTrying = (u_char)0; u_char forceRoutable = FALSE; u_char maskMode = MASK_AUTO; u_char mapType = MAP_OBSTRUCT | DRAW_ROUTES; u_char ripLimit = 10; // Fail net rather than rip up more than // this number of other nets. char DEFfilename[256]; ScaleRec Scales; // record of input and output scales /*--------------------------------------------------------------*/ /* Check track pitch and set the number of channels (may be */ /* called from DefRead) */ /*--------------------------------------------------------------*/ int set_num_channels() { int i; if (NumChannelsX[0] != 0) return; /* Already been called */ for (i = 0; i < Num_layers; i++) { if (PitchX[i] == 0.0 || PitchY[i] == 0.0) { Fprintf(stderr, "Have a 0 pitch for layer %d (of %d). " "Exit.\n", i + 1, Num_layers); return (-3); } NumChannelsX[i] = (int)(1.5 + (Xupperbound - Xlowerbound) / PitchX[i]); NumChannelsY[i] = (int)(1.5 + (Yupperbound - Ylowerbound) / PitchY[i]); if ((Verbose > 1) || (NumChannelsX[i] <= 0)) Fprintf(stdout, "Number of x channels for layer %d is %d\n", i, NumChannelsX[i]); if ((Verbose > 1) || (NumChannelsY[i] <= 0)) Fprintf(stdout, "Number of y channels for layer %d is %d\n", i, NumChannelsY[i]); if (NumChannelsX[i] <= 0) { Fprintf(stderr, "Something wrong with layer %d x bounds.\n", i); return(-3); } if (NumChannelsY[i] <= 0) { Fprintf(stderr, "Something wrong with layer %d y bounds.\n", i); return(-3); } Flush(stdout); } if (recalc_spacing()) draw_layout(); return 0; } /*--------------------------------------------------------------*/ /* Allocate the Obs[] array (may be called from DefRead) */ /*--------------------------------------------------------------*/ int allocate_obs_array() { int i; if (Obs[0] != NULL) return; /* Already been called */ for (i = 0; i < Num_layers; i++) { Obs[i] = (u_int *)calloc(NumChannelsX[i] * NumChannelsY[i], sizeof(u_int)); if (!Obs[i]) { Fprintf(stderr, "Out of memory 4.\n"); return(4); } } return 0; } /*--------------------------------------------------------------*/ /* countlist --- */ /* Count the number of entries in a simple linked list */ /*--------------------------------------------------------------*/ int countlist(NETLIST net) { NETLIST nptr = net; int count = 0; while (nptr != NULL) { count++; nptr = nptr->next; } return count; } /*--------------------------------------------------------------*/ /* runqrouter - main program entry point, parse command line */ /* */ /* ARGS: argc (count) argv, command line */ /* RETURNS: to OS */ /* SIDE EFFECTS: */ /*--------------------------------------------------------------*/ int runqrouter(int argc, char *argv[]) { int i, j, result; int length, width; FILE *l, *configFILEptr, *fptr, *infoFILEptr; u_int u; static char configdefault[] = CONFIGFILENAME; char *configfile = configdefault; char *infofile = NULL; char *dotptr, *sptr; char Filename[256]; double sreq; NET net; u_char readconfig = FALSE; Scales.iscale = 1; Filename[0] = 0; DEFfilename[0] = 0; while ((i = getopt(argc, argv, "c:i:hk:fv:p:g:r:")) != -1) { switch (i) { case 'c': configfile = strdup(optarg); break; case 'v': Verbose = atoi(optarg); break; case 'i': infofile = strdup(optarg); break; case 'p': vddnet = strdup(optarg); break; case 'g': gndnet = strdup(optarg); break; case 'r': if (sscanf(optarg, "%d", &Scales.iscale) != 1) { Fprintf(stderr, "Bad resolution scalefactor \"%s\", " "integer expected.\n", optarg); Scales.iscale = 1; } break; case 'h': helpmessage(); return 1; break; case 'f': forceRoutable = 1; break; case 'k': keepTrying = (u_char)atoi(optarg); break; default: Fprintf(stderr, "bad switch %d\n", i); } } if (infofile != NULL) infoFILEptr = fopen(infofile, "w" ); else infoFILEptr = NULL; configFILEptr = fopen(configfile, "r"); if (configFILEptr) { read_config(configFILEptr, (infoFILEptr == NULL) ? FALSE : TRUE); readconfig = TRUE; } else { if (configfile != configdefault) Fprintf(stderr, "Could not open %s\n", configfile ); else Fprintf(stdout, "No .cfg file specified, continuing without.\n"); } if (configfile != configdefault) free(configfile); if (infoFILEptr != NULL) { /* Print qrouter name and version number at the top */ #ifdef TCL_QROUTER fprintf(infoFILEptr, "qrouter %s.%s.T\n", VERSION, REVISION); #else fprintf(infoFILEptr, "qrouter %s.%s\n", VERSION, REVISION); #endif /* Resolve pitches. This is normally done after reading */ /* the DEF file, but the info file is usually generated */ /* from LEF layer information only, in order to get the */ /* values needed to write the DEF file tracks. */ for (i = 0; i < Num_layers; i++) { int o = LefGetRouteOrientation(i); /* Set PitchX and PitchY from route info as */ /* check_variable_pitch needs the values */ if (o == 1) PitchY[i] = LefGetRoutePitch(i); else PitchX[i] = LefGetRoutePitch(i); } /* Resolve pitch information similarly to post_config() */ for (i = 1; i < Num_layers; i++) { int o = LefGetRouteOrientation(i); if ((o == 1) && (PitchY[i - 1] == 0)) PitchY[i - 1] = PitchY[i]; else if ((o == 0) && (PitchX[i - 1] == 0)) PitchX[i - 1] = PitchX[i]; } /* Print information about route layers, and exit */ for (i = 0; i < Num_layers; i++) { int vnum, hnum; int o = LefGetRouteOrientation(i); char *layername = LefGetRouteName(i); check_variable_pitch(i, &hnum, &vnum); if (vnum > 1 && hnum == 1) hnum++; // see note in node.c if (hnum > 1 && vnum == 1) vnum++; if (layername != NULL) { fprintf(infoFILEptr, "%s %g %g %g %s", layername, (o == 1) ? PitchY[i] : PitchX[i], LefGetRouteOffset(i), LefGetRouteWidth(i), (o == 1) ? "horizontal" : "vertical"); if (o == 1 && vnum > 1) fprintf(infoFILEptr, " %d", vnum); else if (o == 0 && hnum > 1) fprintf(infoFILEptr, " %d", hnum); fprintf(infoFILEptr, "\n"); } } fclose(infoFILEptr); return 1; } if (optind < argc) { /* process remaining commandline strings */ strcpy( Filename, argv[optind] ); dotptr = strrchr(Filename, '.'); if (dotptr != NULL) *dotptr = '\0'; sprintf(DEFfilename, "%s.def", Filename); } else if (readconfig) { Fprintf(stdout, "No netlist file specified, continuing without.\n"); helpmessage(); return 1; } Obs[0] = (u_int *)NULL; NumChannelsX[0] = 0; // This is so we can check if NumChannelsX/Y were // set from within DefRead() due to reading in // existing nets. Scales.oscale = 1.0; return 0; } /*--------------------------------------------------------------*/ /* reinitialize --- */ /* */ /* Free up memory in preparation for reading another DEF file */ /*--------------------------------------------------------------*/ void reinitialize() { int i; NETLIST nl; NET net; ROUTE rt; SEG seg; DSEG obs, tap; NODE node; GATE gate; DPOINT dpt; // Free up all of the matrices for (i = 0; i < Pinlayers; i++) { free(Stub[i]); free(Nodeloc[i]); free(Nodesav[i]); Stub[i] = NULL; Nodeloc[i] = NULL; Nodesav[i] = NULL; } for (i = 0; i < Num_layers; i++) { free(Obs2[i]); free(Obs[i]); Obs2[i] = NULL; Obs[i] = NULL; } if (RMask != NULL) { free(RMask); RMask = NULL; } // Free the netlist of failed nets (if there is one) while (FailedNets) { nl = FailedNets; FailedNets = FailedNets->next; free(nl); } // Free all net and route information for (i = 0; i < Numnets; i++) { net = Nlnets[i]; while (net->noripup) { nl = net->noripup; net->noripup = net->noripup->next; free(nl); } while (net->routes) { rt = net->routes; net->routes = net->routes->next; while (rt->segments) { seg = rt->segments; rt->segments = rt->segments->next; free(seg); } free(rt); } while (net->netnodes) { node = net->netnodes; net->netnodes = net->netnodes->next; while (node->taps) { dpt = node->taps; node->taps = node->taps->next; free(dpt); } while (node->extend) { dpt = node->extend; node->extend = node->extend->next; free(dpt); } // Note: node->netname is not allocated // but copied from net record free(node); } free (net->netname); free (net); } free(Nlnets); Nlnets = NULL; Numnets = 0; // Free all gates information while (Nlgates) { gate = Nlgates; Nlgates = Nlgates->next; while (gate->obs) { obs = gate->obs; gate->obs = gate->obs->next; free(obs); } for (i = 0; i < gate->nodes; i++) { while (gate->taps[i]) { tap = gate->taps[i]; gate->taps[i] = gate->taps[i]->next; free(tap); } // Note: gate->node[i] is not allocated // but copied from cell record in GateInfo // Likewise for gate->noderec[i] } free(gate->gatename); } Nlgates = NULL; } /*--------------------------------------------------------------*/ /* post_def_setup --- */ /* */ /* Things to do after a DEF file has been read in, and the size */ /* of the layout, components, and nets are known. */ /*--------------------------------------------------------------*/ int post_def_setup() { NET net; int i; double sreq1, sreq2; if (DEFfilename[0] == '\0') { Fprintf(stderr, "No DEF file read, nothing to set up.\n"); return 1; } else { if (Num_layers <= 0) { Fprintf(stderr, "No routing layers defined, nothing to do.\n"); return 1; } } for (i = 0; i < Numnets; i++) { net = Nlnets[i]; find_bounding_box(net); defineRouteTree(net); } create_netorder(0); // Choose ordering method (0 or 1) set_num_channels(); // If not called from DefRead() allocate_obs_array(); // If not called from DefRead() initMask(); for (i = 0; i < Num_layers; i++) { Obsinfo[i] = (float *)calloc(NumChannelsX[i] * NumChannelsY[i], sizeof(float)); if (!Obsinfo[i]) { fprintf(stderr, "Out of memory 5.\n"); exit(5); } Stub[i] = (float *)calloc(NumChannelsX[i] * NumChannelsY[i], sizeof(float)); if (!Stub[i]) { fprintf( stderr, "Out of memory 6.\n"); exit(6); } // Nodeloc is the reverse lookup table for nodes Nodeloc[i] = (NODE *)calloc(NumChannelsX[i] * NumChannelsY[i], sizeof(NODE)); if (!Nodeloc[i]) { fprintf(stderr, "Out of memory 7.\n"); exit(7); } Nodesav[i] = (NODE *)calloc(NumChannelsX[i] * NumChannelsY[i], sizeof(NODE)); if (!Nodesav[i]) { fprintf(stderr, "Out of memory 8.\n"); exit(8); } } Flush(stdout); if (Verbose > 1) Fprintf(stderr, "Diagnostic: memory block is %d bytes\n", sizeof(u_int) * NumChannelsX[0] * NumChannelsY[0]); /* Be sure to create obstructions from gates first, since we don't */ /* want improperly defined or positioned obstruction layers to over- */ /* write our node list. */ expand_tap_geometry(); create_obstructions_from_gates(); create_obstructions_inside_nodes(); create_obstructions_outside_nodes(); tap_to_tap_interactions(); create_obstructions_from_variable_pitch(); adjust_stub_lengths(); find_route_blocks(); count_reachable_taps(); count_pinlayers(); // If any nets are pre-routed, place those routes. for (i = 0; i < Numnets; i++) { net = Nlnets[i]; writeback_all_routes(net); } // Remove the Obsinfo array, which is no longer needed, and allocate // the Obs2 array for costing information for (i = 0; i < Num_layers; i++) free(Obsinfo[i]); for (i = 0; i < Num_layers; i++) { Obs2[i] = (PROUTE *)calloc(NumChannelsX[i] * NumChannelsY[i], sizeof(PROUTE)); if (!Obs2[i]) { fprintf( stderr, "Out of memory 9.\n"); exit(9); } } // Fill in needblock bit fields, which are used by commit_proute // when route layers are too large for the grid size, and grid points // around a route need to be marked as blocked whenever something is // routed on those layers. // "ROUTEBLOCK" is set if the spacing is violated between a normal // route and an adjacent via. "VIABLOCK" is set if the spacing is // violated between two adjacent vias. It may be helpful to define // a third category which is route-to-route spacing violation. for (i = 0; i < Num_layers; i++) { needblock[i] = (u_char)0; sreq1 = LefGetRouteSpacing(i); sreq2 = LefGetViaWidth(i, i, 0) + sreq1; if ((sreq2 - EPS) > PitchX[i]) needblock[i] |= VIABLOCKX; if (i != 0) { sreq2 = LefGetViaWidth(i - 1, i, 0) + sreq1; if ((sreq2 - EPS) > PitchX[i]) needblock[i] |= VIABLOCKX; } sreq2 = LefGetViaWidth(i, i, 1) + sreq1; if ((sreq2 - EPS) > PitchY[i]) needblock[i] |= VIABLOCKY; if (i != 0) { sreq2 = LefGetViaWidth(i - 1, i, 1) + sreq1; if ((sreq2 - EPS) > PitchY[i]) needblock[i] |= VIABLOCKY; } sreq1 += 0.5 * LefGetRouteWidth(i); sreq2 = sreq1 + 0.5 * LefGetViaWidth(i, i, 0); if ((sreq2 - EPS) > PitchX[i]) needblock[i] |= ROUTEBLOCKX; if (i != 0) { sreq2 = sreq1 + 0.5 * LefGetViaWidth(i - 1, i, 0); if ((sreq2 - EPS) > PitchX[i]) needblock[i] |= ROUTEBLOCKX; } sreq2 = sreq1 + 0.5 * LefGetViaWidth(i, i, 1); if ((sreq2 - EPS) > PitchY[i]) needblock[i] |= ROUTEBLOCKY; if (i != 0) { sreq2 = sreq1 + 0.5 * LefGetViaWidth(i - 1, i, 1); if ((sreq2 - EPS) > PitchY[i]) needblock[i] |= ROUTEBLOCKY; } } // Now we have netlist data, and can use it to get a list of nets. FailedNets = (NETLIST)NULL; Flush(stdout); if (Verbose > 0) Fprintf(stdout, "There are %d nets in this design.\n", Numnets); return 0; } /*--------------------------------------------------------------*/ /* read_def --- */ /* */ /* Read in the DEF file in DEFfilename */ /*--------------------------------------------------------------*/ void read_def(char *filename) { if ((filename == NULL) && (DEFfilename[0] == '\0')) { Fprintf(stderr, "No DEF file specified, nothing to read.\n"); return; } else if (filename != NULL) { if (DEFfilename[0] != '\0') reinitialize(); strcpy(DEFfilename, filename); } else reinitialize(); Scales.oscale = (double)((float)Scales.iscale * DefRead(DEFfilename)); post_def_setup(); } /*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/ int dofirststage(u_char graphdebug, int debug_netnum) { int i, failcount, remaining, result; NET net; NETLIST nl; // Clear the lists of failed routes, in case first // stage is being called more than once. if (debug_netnum <= 0) { while (FailedNets) { nl = FailedNets->next; free(FailedNets); FailedNets = nl; } } // Now find and route all the nets remaining = Numnets; for (i = (debug_netnum >= 0) ? debug_netnum : 0; i < Numnets; i++) { net = getnettoroute(i); if ((net != NULL) && (net->netnodes != NULL)) { result = doroute(net, (u_char)0, graphdebug); if (result == 0) { remaining--; if (Verbose > 0) Fprintf(stdout, "Finished routing net %s\n", net->netname); Fprintf(stdout, "Nets remaining: %d\n", remaining); } else { if (Verbose > 0) Fprintf(stdout, "Failed to route net %s\n", net->netname); } } else { if (net && (Verbose > 0)) { Fprintf(stdout, "Nothing to do for net %s\n", net->netname); } remaining--; } if (debug_netnum >= 0) break; } failcount = countlist(FailedNets); if (debug_netnum >= 0) return failcount; if (Verbose > 0) { Flush(stdout); Fprintf(stdout, "\n----------------------------------------------\n"); Fprintf(stdout, "Progress: "); Fprintf(stdout, "Stage 1 total routes completed: %d\n", TotalRoutes); } if (FailedNets == (NETLIST)NULL) Fprintf(stdout, "No failed routes!\n"); else { if (FailedNets != (NETLIST)NULL) Fprintf(stdout, "Failed net routes: %d\n", failcount); } if (Verbose > 0) Fprintf(stdout, "----------------------------------------------\n"); return failcount; } /*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/ int write_def(char *filename) { NET net; NETLIST nl; // Finish up by writing the routes to an annotated DEF file emit_routes((filename == NULL) ? DEFfilename : filename, Scales.oscale, Scales.iscale); Fprintf(stdout, "----------------------------------------------\n"); Fprintf(stdout, "Final: "); if (FailedNets == (NETLIST)NULL) Fprintf(stdout, "No failed routes!\n"); else { if (FailedNets != (NETLIST)NULL) { Fprintf(stdout, "Failed net routes: %d\n", countlist(FailedNets)); Fprintf(stdout, "List of failed nets follows:\n"); // Make sure FailedNets is cleaned up as we output the failed nets while (FailedNets) { net = FailedNets->net; Fprintf(stdout, " %s\n", net->netname); nl = FailedNets->next; free(FailedNets); FailedNets = nl; } Fprintf(stdout, "\n"); } } Fprintf(stdout, "----------------------------------------------\n"); return 0; } /* write_def() */ /*--------------------------------------------------------------*/ /* pathstart - begin a DEF format route path */ /* */ /* If "special" is true, then this path is in a */ /* SPECIALNETS section, in which each route specifies */ /* a width. */ /*--------------------------------------------------------------*/ void pathstart(FILE *cmd, int layer, int x, int y, u_char special, double oscale, double invscale, u_char horizontal) { if (Pathon == 1) { Fprintf( stderr, "pathstart(): Major error. Started a new " "path while one is in progress!\n" "Doing it anyway.\n" ); } if (layer >= 0) { if (Pathon == -1) fprintf(cmd, "+ ROUTED "); else fprintf(cmd, "\n NEW "); if (special) { double wvia; wvia = LefGetViaWidth(layer, layer, horizontal); if (layer > 0) { double wvia2; wvia2 = LefGetViaWidth(layer - 1, layer, horizontal); if (wvia2 > wvia) wvia = wvia2; } fprintf(cmd, "%s %g ( %g %g ) ", CIFLayer[layer], invscale * (int)(oscale * wvia + 0.5), invscale * x, invscale * y); } else fprintf(cmd, "%s ( %g %g ) ", CIFLayer[layer], invscale * x, invscale * y); } Pathon = 1; } /* pathstart() */ /*--------------------------------------------------------------*/ /* pathto - continue a path to the next point */ /* */ /* ARGS: coordinate pair */ /* RETURNS: */ /* SIDE EFFECTS: */ /*--------------------------------------------------------------*/ void pathto(FILE *cmd, int x, int y, int horizontal, int lastx, int lasty, double invscale) { if (Pathon <= 0) { Fprintf(stderr, "pathto(): Major error. Added to a " "non-existent path!\n" "Doing it anyway.\n"); } /* If the route is not manhattan, then it's because an offset * was added to the last point, and we need to add a small * jog to the route. */ if ((x != lastx) && (y != lasty)) { if (horizontal) pathto(cmd, x, y, FALSE, x, lasty, invscale); else pathto(cmd, x, y, TRUE, lastx, y, invscale); } fprintf(cmd, "( "); if (horizontal) fprintf(cmd, "%g ", invscale * x); else fprintf(cmd, "* "); if (horizontal) fprintf(cmd, "* "); else fprintf(cmd, "%g ", invscale * y); fprintf(cmd, ") "); } /* pathto() */ /*--------------------------------------------------------------*/ /* pathvia - add a via to a path */ /* */ /* ARGS: coord */ /* RETURNS: */ /* SIDE EFFECTS: */ /*--------------------------------------------------------------*/ void pathvia(FILE *cmd, int layer, int x, int y, int lastx, int lasty, int gridx, int gridy, double invscale) { char *s; char checkersign = (gridx + gridy + layer) & 0x01; if ((ViaPattern == VIA_PATTERN_NONE) || (ViaY[layer] == NULL)) s = ViaX[layer]; else if (ViaPattern == VIA_PATTERN_NORMAL) s = (checkersign == 0) ? ViaX[layer] : ViaY[layer]; else s = (checkersign == 0) ? ViaY[layer] : ViaX[layer]; if (Pathon <= 0) { if (Pathon == -1) fprintf(cmd, "+ ROUTED "); else fprintf(cmd, "\n NEW "); fprintf(cmd, "%s ( %g %g ) ", CIFLayer[layer], invscale * x, invscale * y); } else { // Normally the path will be manhattan and only one of // these will be true. But if the via gets an offset to // avoid a DRC spacing violation with an adjacent via, // then we may need to apply both paths to make a dog-leg // route to the via. if (x != lastx) pathto(cmd, x, y, TRUE, lastx, y, invscale); if (y != lasty) pathto(cmd, x, y, FALSE, x, lasty, invscale); } fprintf(cmd, "%s ", s); Pathon = 0; } /* pathvia() */ /*--------------------------------------------------------------*/ /* Nodes aren't saved in a way that makes it easy to recall */ /* the name of the cell and pin to which they belong. But */ /* that information doesn't need to be looked up except as a */ /* diagnostic output. This routine does that lookup. */ /*--------------------------------------------------------------*/ char *print_node_name(NODE node) { GATE g; int i; static char *nodestr = NULL; for (g = Nlgates; g; g = g->next) { for (i = 0; i < g->nodes; i++) { if (g->noderec[i] == node) { if (nodestr != NULL) free(nodestr); nodestr = (char *)malloc(strlen(g->gatename) + strlen(g->node[i]) + 2); sprintf(nodestr, "%s/%s", g->gatename, g->node[i]); return nodestr; } } } if (nodestr != NULL) free(nodestr); nodestr = (char *)malloc(22); sprintf(nodestr, "(error: no such node)"); return nodestr; } /*--------------------------------------------------------------*/ /* print_nets - print the nets list - created from Nlgates list */ /* */ /* ARGS: filename to list to */ /* RETURNS: nothing */ /* SIDE EFFECTS: */ /* AUTHOR and DATE: steve beccue Sat July 26 */ /*--------------------------------------------------------------*/ void print_nets(char *filename) { FILE *o; GATE g; int i; DSEG drect; if (!strcmp(filename, "stdout")) { o = stdout; } else { o = fopen(filename, "w"); } if (!o) { Fprintf(stderr, "route:print_nets. Couldn't open output file\n"); return; } for (g = Nlgates; g; g = g->next) { fprintf(o, "%s: %s: nodes->", g->gatename, g->gatetype->gatename); for (i = 0; i < g->nodes; i++) { // This prints the first tap position only. drect = g->taps[i]; fprintf( o, "%s(%g,%g) ", g->node[i], drect->x1, drect->y1); } } fprintf( o, "\n"); } /* print_nets() */ /*--------------------------------------------------------------*/ /* print_routes - print the routes list */ /* */ /* ARGS: filename to list to */ /* RETURNS: nothing */ /* SIDE EFFECTS: */ /* AUTHOR and DATE: steve beccue Sat July 26 */ /*--------------------------------------------------------------*/ void print_routes( char *filename ) { FILE *o; GATE g; int i; if( !strcmp( filename, "stdout" ) ) { o = stdout; } else { o = fopen( filename, "w" ); } if( !o ) { Fprintf( stderr, "route:print_routes. Couldn't open output file\n" ); return; } for (g = Nlgates; g; g = g->next) { fprintf( o, "%s: %s: nodes->", g->gatename, g->gatetype->gatename ); for( i = 0 ; i < g->nodes; i++ ) { fprintf( o, "%s ", g->node[i] ); } fprintf(o, "\n"); } } /* print_routes() */ /*--------------------------------------------------------------*/ /* print_nlgates - print the nlgate list */ /* */ /* ARGS: filename to list to */ /* RETURNS: nothing */ /* SIDE EFFECTS: */ /* AUTHOR and DATE: steve beccue Wed July 23 */ /*--------------------------------------------------------------*/ void print_nlgates( char *filename ) { FILE *o; GATE g; int i; DSEG drect; if( !strcmp( filename, "stdout" ) ) { o = stdout; } else { o = fopen( filename, "w" ); } if( !o ) { Fprintf( stderr, "route:print_nlgates. Couldn't open output file\n" ); return; } for (g = Nlgates; g; g = g->next) { fprintf( o, "%s: %s: nodes->", g->gatename, g->gatetype->gatename ); for( i = 0 ; i < g->nodes; i++ ) { // This prints the first tap position only. drect = g->taps[i]; fprintf( o, "%s(%g,%g)", g->node[i], drect->x1, drect->y1); } fprintf(o, "\n"); } } /* print_nlgates() */ /*--------------------------------------------------------------*/ /* getnettoroute - get a net to route */ /* */ /* ARGS: */ /* RETURNS: */ /* SIDE EFFECTS: */ /* AUTHOR and DATE: steve beccue Fri Aug 8 */ /*--------------------------------------------------------------*/ NET getnettoroute(int order) { NET net; net = Nlnets[order]; if (net == NULL) return NULL; if (net->flags & NET_IGNORED) return NULL; if (net->numnodes >= 2) return net; // Qrouter will route power and ground nets even if the // standard cell power and ground pins are not listed in // the nets section. Because of this, it is okay to have // only one node. if ((net->numnodes == 1) && (net->netnum == VDD_NET || net->netnum == GND_NET)) return net; if (Verbose > 3) { Flush(stdout); Fprintf(stderr, "getnettoroute(): Fell through\n"); } return NULL; } /* getnettoroute() */ /*--------------------------------------------------------------*/ /* Find all routes that collide with net "net", remove them */ /* from the Obs[] matrix, append them to the FailedNets list, */ /* and then write the net "net" back to the Obs[] matrix. */ /* */ /* Return the number of nets ripped up */ /*--------------------------------------------------------------*/ int ripup_colliding(NET net) { NETLIST nl, nl2, fn; int ripped; // Analyze route for nets with which it collides nl = find_colliding(net, &ripped); // "ripLimit" limits the number of collisions so that the // router avoids ripping up huge numbers of nets, which can // cause the number of failed nets to keep increasing. if (ripped > ripLimit) { while (nl) { nl2 = nl->next; free(nl); nl = nl2; } return -1; } // Remove the colliding nets from the route grid and append // them to FailedNets. ripped = 0; while(nl) { ripped++; nl2 = nl->next; if (Verbose > 0) Fprintf(stdout, "Ripping up blocking net %s\n", nl->net->netname); if (ripup_net(nl->net, (u_char)1) == TRUE) { for (fn = FailedNets; fn && fn->next != NULL; fn = fn->next); if (fn) fn->next = nl; else FailedNets = nl; // Add nl->net to "noripup" list for this net, so it won't be // routed over again by the net. Avoids infinite looping in // the second stage. fn = (NETLIST)malloc(sizeof(struct netlist_)); fn->next = net->noripup; net->noripup = fn; fn->net = nl->net; } nl->next = (NETLIST)NULL; nl = nl2; } return ripped; } /*--------------------------------------------------------------*/ /* Do a second-stage route (rip-up and re-route) of a single */ /* net "net". */ /*--------------------------------------------------------------*/ int route_net_ripup(NET net, u_char graphdebug) { int result; NETLIST nl, nl2; // Find the net in the Failed list and remove it. if (FailedNets) { if (FailedNets->net == net) { nl2 = FailedNets; FailedNets = FailedNets->next; free(nl2); } else { for (nl = FailedNets; nl->next; nl = nl->next) { if (nl->next->net == net) break; } nl2 = nl->next; nl->next = nl2->next; free(nl2); } } result = doroute(net, (u_char)1, graphdebug); if (result != 0) { if (net->noripup != NULL) { if ((net->flags & NET_PENDING) == 0) { // Clear this net's "noripup" list and try again. while (net->noripup) { nl = net->noripup->next; free(net->noripup); net->noripup = nl; } result = doroute(net, (u_char)1, graphdebug); net->flags |= NET_PENDING; // Next time we abandon it. } } } if (result != 0) result = ripup_colliding(net); return result; } /*--------------------------------------------------------------*/ /* dosecondstage() --- */ /* */ /* Second stage: Rip-up and reroute failing nets. */ /* Method: */ /* 1) Route a failing net with stage = 1 (other nets become */ /* costs, not blockages, no copying to Obs) */ /* 2) If net continues to fail, flag it as unroutable and */ /* remove it from the list. */ /* 3) Otherwise, determine the nets with which it collided. */ /* 4) Remove all of the colliding nets, and add them to the */ /* FailedNets list */ /* 5) Route the original failing net. */ /* 6) Continue until all failed nets have been processed. */ /* */ /* Return value: The number of failing nets */ /*--------------------------------------------------------------*/ int dosecondstage(u_char graphdebug, u_char singlestep) { int failcount, origcount, result, maxtries, lasttries; NET net; NETLIST nl, nl2, fn; NETLIST Abandoned; // Abandoned routes---not even trying any more. ROUTE rt, rt2; SEG seg; origcount = countlist(FailedNets); if (FailedNets) maxtries = TotalRoutes + ((origcount < 20) ? 20 : origcount) * 8; else maxtries = 0; fillMask((u_char)0); Abandoned = NULL; // Clear the "noripup" field from all of the failed nets, in case // the second stage route is being repeated. for (nl2 = FailedNets; nl2; nl2 = nl2->next) { net = nl2->net; while (net->noripup) { nl = net->noripup->next; free(net->noripup); net->noripup = nl; } net->flags &= ~NET_PENDING; } while (FailedNets != NULL) { // Diagnostic: how are we doing? failcount = countlist(FailedNets); if (Verbose > 1) Fprintf(stdout, "------------------------------\n"); Fprintf(stdout, "Nets remaining: %d\n", failcount); if (Verbose > 1) Fprintf(stdout, "------------------------------\n"); net = FailedNets->net; // Remove this net from the fail list nl2 = FailedNets; FailedNets = FailedNets->next; free(nl2); // Keep track of which routes existed before the call to doroute(). for (rt = net->routes; rt && rt->next; rt = rt->next); if (Verbose > 2) Fprintf(stdout, "Routing net %s with collisions\n", net->netname); Flush(stdout); result = doroute(net, (u_char)1, graphdebug); if (result != 0) { if (net->noripup != NULL) { if ((net->flags & NET_PENDING) == 0) { // Clear this net's "noripup" list and try again. while (net->noripup) { nl = net->noripup->next; free(net->noripup); net->noripup = nl; } result = doroute(net, (u_char)1, graphdebug); net->flags |= NET_PENDING; // Next time we abandon it. } } } if (result == 0) { // Find nets that collide with "net" and remove them, adding them // to the end of the FailedNets list. // If the number of nets to be ripped up exceeds "ripLimit", // then treat this as a route failure, and don't rip up any of // the colliding nets. result = ripup_colliding(net); if (result > 0) result = 0; } if (result != 0) { // Complete failure to route, even allowing collisions. // Abandon routing this net. if (Verbose > 0) { Flush(stdout); Fprintf(stderr, "----------------------------------------------\n"); Fprintf(stderr, "Complete failure on net %s: Abandoning.\n", net->netname); Fprintf(stderr, "----------------------------------------------\n"); } // Add the net to the "abandoned" list nl = (NETLIST)malloc(sizeof(struct netlist_)); nl->net = net; nl->next = Abandoned; Abandoned = nl; while (FailedNets && (FailedNets->net == net)) { nl = FailedNets->next; free(FailedNets); FailedNets = nl; } // Remove routing information for all new routes that have // not been copied back into Obs[]. if (rt == NULL) rt = net->routes; else { rt2 = rt->next; rt->next = NULL; rt = rt2; } while (rt != NULL) { rt2 = rt->next; while (rt->segments) { seg = rt->segments->next; free(rt->segments); rt->segments = seg; } rt = rt2; } // Remove both routing information and remove the route from // Obs[] for all parts of the net that were previously routed ripup_net(net, (u_char)1); // Remove routing information from net continue; } // Write back the original route to the grid array writeback_all_routes(net); // Failsafe---if we have been looping enough times to exceed // maxtries (which is set to 8 route attempts per original failed // net), then we check progress. If we have reduced the number // of failed nets by half or more, then we have an indication of // real progress, and will continue. If not, we give up. Qrouter // is almost certainly hopelessly stuck at this point. if (TotalRoutes >= maxtries) { if (failcount <= (origcount / 2)) { maxtries = TotalRoutes + failcount * 8; origcount = failcount; } else if (keepTrying == 0) { Fprintf(stderr, "\nQrouter is stuck, abandoning remaining routes.\n"); break; } else { keepTrying--; Fprintf(stderr, "\nQrouter is stuck, but I was told to keep trying.\n"); maxtries = TotalRoutes + failcount * 8; origcount = failcount; } } if (singlestep && (FailedNets != NULL)) return countlist(FailedNets); } // If the list of abandoned nets is non-null, attach it to the // end of the failed nets list. if (Abandoned != NULL) { if (FailedNets == NULL) { FailedNets = Abandoned; Abandoned = NULL; } else { for (nl = FailedNets; nl->next; nl = nl->next); nl->next = Abandoned; Abandoned = NULL; } } if (Verbose > 0) { Flush(stdout); Fprintf(stdout, "\n----------------------------------------------\n"); Fprintf(stdout, "Progress: "); Fprintf(stdout, "Stage 2 total routes completed: %d\n", TotalRoutes); } if (FailedNets == (NETLIST)NULL) { failcount = 0; Fprintf(stdout, "No failed routes!\n"); } else { failcount = countlist(FailedNets); if (FailedNets != (NETLIST)NULL) Fprintf(stdout, "Failed net routes: %d\n", failcount); } if (Verbose > 0) Fprintf(stdout, "----------------------------------------------\n"); return failcount; } /*--------------------------------------------------------------*/ /* initMask() --- */ /*--------------------------------------------------------------*/ void initMask() { RMask = (u_char *)calloc(NumChannelsX[0] * NumChannelsY[0], sizeof(u_char)); if (!RMask) { fprintf(stderr, "Out of memory 3.\n"); exit(3); } } /*--------------------------------------------------------------*/ /* Fill mask around the area of a vertical line */ /*--------------------------------------------------------------*/ void create_vbranch_mask(int x, int y1, int y2, u_char slack, u_char halo) { int gx1, gx2, gy1, gy2; int i, j, v; u_char m; gx1 = x - slack; gx2 = x + slack; if (y1 > y2) { gy1 = y2 - slack; gy2 = y1 + slack; } else { gy1 = y1 - slack; gy2 = y2 + slack; } if (gx1 < 0) gx1 = 0; if (gx2 >= NumChannelsX[0]) gx2 = NumChannelsX[0] - 1; if (gy1 < 0) gy1 = 0; if (gy2 >= NumChannelsY[0]) gy2 = NumChannelsY[0] - 1; for (i = gx1; i <= gx2; i++) for (j = gy1; j <= gy2; j++) RMask[OGRID(i, j, 0)] = (u_char)0; for (v = 1; v < halo; v++) { if (gx1 > 0) gx1--; if (gx2 < NumChannelsX[0] - 1) gx2++; if (y1 > y2) { if (gy1 < NumChannelsY[0] - 1) gy1++; if (gy2 < NumChannelsY[0] - 1) gy2++; } else { if (gy1 > 0) gy1--; if (gy2 > 0) gy2--; } for (i = gx1; i <= gx2; i++) for (j = gy1; j <= gy2; j++) { m = RMask[OGRID(i, j, 0)]; if (m > v) RMask[OGRID(i, j, 0)] = (u_char)v; } } } /*--------------------------------------------------------------*/ /* Fill mask around the area of a horizontal line */ /*--------------------------------------------------------------*/ void create_hbranch_mask(int y, int x1, int x2, u_char slack, u_char halo) { int gx1, gx2, gy1, gy2; int i, j, v; u_char m; gy1 = y - slack; gy2 = y + slack; if (x1 > x2) { gx1 = x2 - slack; gx2 = x1 + slack; } else { gx1 = x1 - slack; gx2 = x2 + slack; } if (gx1 < 0) gx1 = 0; if (gx2 >= NumChannelsX[0]) gx2 = NumChannelsX[0] - 1; if (gy1 < 0) gy1 = 0; if (gy2 >= NumChannelsY[0]) gy2 = NumChannelsY[0] - 1; for (i = gx1; i <= gx2; i++) for (j = gy1; j <= gy2; j++) RMask[OGRID(i, j, 0)] = (u_char)0; for (v = 1; v < halo; v++) { if (gy1 > 0) gy1--; if (gy2 < NumChannelsY[0] - 1) gy2++; if (x1 > x2) { if (gx1 < NumChannelsX[0] - 1) gx1++; if (gx2 < NumChannelsX[0] - 1) gx2++; } else { if (gx1 > 0) gx1--; if (gx2 > 0) gx2--; } for (i = gx1; i <= gx2; i++) for (j = gy1; j <= gy2; j++) { m = RMask[OGRID(i, j, 0)]; if (m > v) RMask[OGRID(i, j, 0)] = (u_char)v; } } } /*--------------------------------------------------------------*/ /* createBboxMask() --- */ /* */ /* Create mask limiting the area to search for routing */ /* */ /* The bounding box mask generates an area including the */ /* bounding box as defined in the net record, includes all pin */ /* positions in the mask, and increases the mask area by one */ /* route track for each pass, up to "halo". */ /*--------------------------------------------------------------*/ void createBboxMask(NET net, u_char halo) { int xmin, ymin, xmax, ymax; int i, j, gx1, gy1, gx2, gy2; fillMask((u_char)halo); xmin = net->xmin; xmax = net->xmax; ymin = net->ymin; ymax = net->ymax; for (gx1 = xmin; gx1 <= xmax; gx1++) for (gy1 = ymin; gy1 <= ymax; gy1++) RMask[OGRID(gx1, gy1, 0)] = (u_char)0; for (i = 1; i <= halo; i++) { gx1 = xmin - i; if (gx1 >= 0 && gx1 < NumChannelsX[0]) for (j = ymin - i; j <= ymax + i; j++) if (j >= 0 && j < NumChannelsY[0]) RMask[OGRID(gx1, j, 0)] = (u_char)i; gx2 = xmax + i; if (gx2 >= 0 && gx2 < NumChannelsX[0]) for (j = ymin - i; j <= ymax + i; j++) if (j >= 0 && j < NumChannelsY[0]) RMask[OGRID(gx2, j, 0)] = (u_char)i; gy1 = ymin - i; if (gy1 >= 0 && gy1 < NumChannelsY[0]) for (j = xmin - i; j <= xmax + i; j++) if (j >= 0 && j < NumChannelsX[0]) RMask[OGRID(j, gy1, 0)] = (u_char)i; gy2 = ymax + i; if (gy2 >= 0 && gy2 < NumChannelsY[0]) for (j = xmin - i; j <= xmax + i; j++) if (j >= 0 && j < NumChannelsX[0]) RMask[OGRID(j, gy2, 0)] = (u_char)i; } } /*--------------------------------------------------------------*/ /* analyzeCongestion() --- */ /* */ /* Given a trunk route at ycent, between ymin and ymax, score */ /* the neighboring positions as a function of congestion and */ /* offset from the ideal location. Return the position of the */ /* best location for the trunk route. */ /*--------------------------------------------------------------*/ int analyzeCongestion(int ycent, int ymin, int ymax, int xmin, int xmax) { int x, y, i, minidx, sidx, n, o; int *score, minscore; score = (int *)malloc((ymax - ymin + 1) * sizeof(int)); for (y = ymin; y <= ymax; y++) { sidx = y - ymin; score[sidx] = ABSDIFF(ycent, y) * Num_layers; for (x = xmin; x <= xmax; x++) { for (i = 0; i < Num_layers; i++) { n = Obs[i][OGRID(x, y, i)]; if (n & ROUTED_NET) score[sidx]++; if (n & NO_NET) score[sidx]++; if (n & PINOBSTRUCTMASK) score[sidx]++; } } } minscore = MAXRT; for (i = 0; i < (ymax - ymin + 1); i++) { if (score[i] < minscore) { minscore = score[i]; minidx = i + ymin; } } free(score); return minidx; } /*--------------------------------------------------------------*/ /* createMask() --- */ /* */ /* Create mask limiting the area to search for routing */ /* */ /* For 2-node routes, find the two L-shaped routes between the */ /* two closest points of the nodes. */ /* For multi-node (>2) routes, find the best trunk line that */ /* passes close to all nodes, and generate stems to the closest */ /* point on each node. */ /* */ /* Optimizations: (1) multi-node routes that are in a small */ /* enough area, just mask the bounding box. (2) Where nodes */ /* at the end of two branches are closer to each other than to */ /* the trunk, mask an additional cross-connection between the */ /* two branches. */ /* */ /* Values are "halo" where there is no mask, 0 on the */ /* closest "slack" routes to the ideal (typically 1), and */ /* values increasing out to a distance of "halo" tracks away */ /* from the ideal. This allows a greater search area as the */ /* number of passes of the search algorithm increases. */ /* */ /* To do: Choose the position of trunk line based on */ /* congestion analysis. */ /*--------------------------------------------------------------*/ void createMask(NET net, u_char slack, u_char halo) { NODE n1, n2; DPOINT d1tap, d2tap, dtap; int i, j, orient, l, v; int dx, dy, gx1, gx2, gy1, gy2; int xcent, ycent, xmin, ymin, xmax, ymax; int branchx, branchy; fillMask((u_char)halo); xmin = net->xmin; xmax = net->xmax; ymin = net->ymin; ymax = net->ymax; xcent = net->trunkx; ycent = net->trunky; orient = 0; // Construct the trunk line mask if (!(net->flags & NET_VERTICAL_TRUNK) || (net->numnodes == 2)) { // Horizontal trunk orient |= 1; ycent = analyzeCongestion(net->trunky, ymin, ymax, xmin, xmax); ymin = ymax = ycent; for (i = xmin - slack; i <= xmax + slack; i++) { if (i < 0 || i >= NumChannelsX[0]) continue; for (j = ycent - slack; j <= ycent + slack; j++) { if (j < 0 || j >= NumChannelsY[0]) continue; RMask[OGRID(i, j, 0)] = (u_char)0; } } for (i = 1; i < halo; i++) { gy1 = ycent - slack - i; gy2 = ycent + slack + i; for (j = xmin - slack - i; j <= xmax + slack + i; j++) { if (j < 0 || j >= NumChannelsX[0]) continue; if (gy1 >= 0) RMask[OGRID(j, gy1, 0)] = (u_char)i; if (gy2 < NumChannelsY[0]) RMask[OGRID(j, gy2, 0)] = (u_char)i; } gx1 = xmin - slack - i; gx2 = xmax + slack + i; for (j = ycent - slack - i; j <= ycent + slack + i; j++) { if (j < 0 || j >= NumChannelsY[0]) continue; if (gx1 >= 0) RMask[OGRID(gx1, j, 0)] = (u_char)i; if (gx2 < NumChannelsX[0]) RMask[OGRID(gx2, j, 0)] = (u_char)i; } } } if ((net->flags & NET_VERTICAL_TRUNK) || (net->numnodes == 2)) { // Vertical trunk orient |= 2; xmin = xmax = xcent; for (i = xcent - slack; i <= xcent + slack; i++) { if (i < 0 || i >= NumChannelsX[0]) continue; for (j = ymin - slack; j <= ymax + slack; j++) { if (j < 0 || j >= NumChannelsY[0]) continue; RMask[OGRID(i, j, 0)] = (u_char)0; } } for (i = 1; i < halo; i++) { gx1 = xcent - slack - i; gx2 = xcent + slack + i; for (j = ymin - slack - i; j <= ymax + slack + i; j++) { if (j < 0 || j >= NumChannelsY[0]) continue; if (gx1 >= 0) RMask[OGRID(gx1, j, 0)] = (u_char)i; if (gx2 < NumChannelsX[0]) RMask[OGRID(gx2, j, 0)] = (u_char)i; } gy1 = ymin - slack - i; gy2 = ymax + slack + i; for (j = xcent - slack - i; j <= xcent + slack + i; j++) { if (j < 0 || j >= NumChannelsX[0]) continue; if (gy1 >= 0) RMask[OGRID(j, gy1, 0)] = (u_char)i; if (gy2 < NumChannelsY[0]) RMask[OGRID(j, gy2, 0)] = (u_char)i; } } } // Construct the branch line masks for (n1 = net->netnodes; n1; n1 = n1->next) { dtap = (n1->taps == NULL) ? n1->extend : n1->taps; if (!dtap) continue; if (orient | 1) // Horizontal trunk, vertical branches create_vbranch_mask(n1->branchx, n1->branchy, ycent, slack, halo); if (orient | 2) // Vertical trunk, horizontal branches create_hbranch_mask(n1->branchy, n1->branchx, xcent, slack, halo); } // Look for branches that are closer to each other than to the // trunk line. If any are found, make a cross-connection between // the branch end that is closer to the trunk and the branch that // is its nearest neighbor. if (orient | 1) { // Horizontal trunk, vertical branches for (n1 = net->netnodes; n1; n1 = n1->next) { for (n2 = net->netnodes->next; n2; n2 = n2->next) { // Check if both ends are on the same side of the trunk if ((n2->branchy > ycent && n1->branchy > ycent) || (n2->branchy < ycent && n1->branchy < ycent)) { // Check if branches are closer to each other than // the shortest branch is away from the trunk dx = ABSDIFF(n2->branchx, n1->branchx); gy1 = ABSDIFF(n1->branchy, ycent); gy2 = ABSDIFF(n2->branchy, ycent); if ((dx < gy1) && (dx < gy2)) { if (gy1 < gy2) create_hbranch_mask(n1->branchy, n2->branchx, n1->branchx, slack, halo); else create_hbranch_mask(n2->branchy, n2->branchx, n1->branchx, slack, halo); } } } } } if (orient | 2) { // Vertical trunk, horizontal branches for (n1 = net->netnodes; n1; n1 = n1->next) { for (n2 = net->netnodes->next; n2; n2 = n2->next) { // Check if both ends are on the same side of the trunk if ((n2->branchx > xcent && n1->branchx > xcent) || (n2->branchx < xcent && n1->branchx < xcent)) { // Check if branches are closer to each other than // the shortest branch is away from the trunk dy = ABSDIFF(n2->branchy, n1->branchy); gx1 = ABSDIFF(n1->branchx, xcent); gx2 = ABSDIFF(n2->branchx, xcent); if ((dy < gx1) && (dy < gx2)) { if (gx1 < gx2) create_vbranch_mask(n1->branchx, n2->branchy, n1->branchy, slack, halo); else create_vbranch_mask(n2->branchx, n2->branchy, n1->branchy, slack, halo); } } } } } // Allow routes at all tap and extension points for (n1 = net->netnodes; n1 != NULL; n1 = n1->next) { for (dtap = n1->taps; dtap != NULL; dtap = dtap->next) RMask[OGRID(dtap->gridx, dtap->gridy, 0)] = (u_char)0; for (dtap = n1->extend; dtap != NULL; dtap = dtap->next) RMask[OGRID(dtap->gridx, dtap->gridy, 0)] = (u_char)0; } if (Verbose > 2) { if (net->numnodes == 2) Fprintf(stdout, "Two-port mask has bounding box (%d %d) to (%d %d)\n", xmin, ymin, xmax, ymax); else Fprintf(stdout, "multi-port mask has trunk line (%d %d) to (%d %d)\n", xmin, ymin, xmax, ymax); } } /*--------------------------------------------------------------*/ /* fillMask() fills the Mask[] array with all 1s as a last */ /* resort, ensuring that no valid routes are missed due to a */ /* bad guess about the optimal route positions. */ /*--------------------------------------------------------------*/ void fillMask(u_char value) { memset((void *)RMask, (int)value, (size_t)(NumChannelsX[0] * NumChannelsY[0] * sizeof(u_char))); } /*--------------------------------------------------------------*/ /* doroute - basic route call */ /* */ /* stage = 0 is normal routing */ /* stage = 1 is the rip-up and reroute stage */ /* */ /* ARGS: two nodes to be connected */ /* RETURNS: 0 on success, -1 on failure */ /* SIDE EFFECTS: */ /* AUTHOR and DATE: steve beccue Fri Aug 8 */ /*--------------------------------------------------------------*/ int doroute(NET net, u_char stage, u_char graphdebug) { POINT gpoint; ROUTE rt1, lrt; NETLIST nlist; int result, lastlayer, unroutable; struct routeinfo_ iroute; if (!net) { Fprintf(stderr, "doroute(): no net to route.\n"); return 0; } CurNet = net; // Global, used by 2nd stage // Fill out route information record iroute.net = net; iroute.rt = NULL; iroute.glist = NULL; iroute.nsrc = NULL; iroute.nsrctap = NULL; iroute.maxcost = MAXRT; iroute.do_pwrbus = (u_char)0; iroute.pwrbus_src = 0; lastlayer = -1; /* Set up Obs2[] matrix for first route */ result = route_setup(&iroute, stage); unroutable = result - 1; if (graphdebug) highlight_mask(); // Keep going until we are unable to route to a terminal while (net && (result > 0)) { if (graphdebug) highlight_source(); if (graphdebug) highlight_dest(); if (graphdebug) highlight_starts(iroute.glist); rt1 = createemptyroute(); rt1->netnum = net->netnum; iroute.rt = rt1; if (Verbose > 3) { Fprintf(stdout,"doroute(): added net %d path start %d\n", net->netnum, net->netnodes->nodenum); } result = route_segs(&iroute, stage, graphdebug); if (result < 0) { // Route failure. // If we failed this on the last round, then stop // working on this net and move on to the next. if (FailedNets && (FailedNets->net == net)) break; nlist = (NETLIST)malloc(sizeof(struct netlist_)); nlist->net = net; nlist->next = FailedNets; FailedNets = nlist; free(rt1); } else { TotalRoutes++; if (net->routes) { for (lrt = net->routes; lrt->next; lrt = lrt->next); lrt->next = rt1; } else { net->routes = rt1; } draw_net(net, TRUE, &lastlayer); } // For power routing, clear the list of existing pending route // solutions---they will not be relevant. if (iroute.do_pwrbus) { while (iroute.glist) { gpoint = iroute.glist; iroute.glist = iroute.glist->next; free(gpoint); } } /* Set up for next route and check if routing is done */ result = next_route_setup(&iroute, stage); } /* Finished routing (or error occurred) */ while (iroute.glist) { gpoint = iroute.glist; iroute.glist = iroute.glist->next; free(gpoint); } /* Route failure due to no taps or similar error---Log it */ if ((result < 0) || (unroutable > 0)) { if ((FailedNets == NULL) || (FailedNets->net != net)) { nlist = (NETLIST)malloc(sizeof(struct netlist_)); nlist->net = net; nlist->next = FailedNets; FailedNets = nlist; } } return result; } /* doroute() */ /*--------------------------------------------------------------*/ /* Catch-all routine when no tap points are found. This is a */ /* common problem when the technology is not set up correctly */ /* and it's helpful to have all these error conditions pass */ /* to a single subroutine. */ /*--------------------------------------------------------------*/ void unable_to_route(char *netname, NODE node, unsigned char forced) { if (node) Fprintf(stderr, "Node %s of net %s has no tap points---", print_node_name(node), netname); else Fprintf(stderr, "Node of net %s has no tap points---", netname); if (forced) Fprintf(stderr, "forcing a tap point.\n"); else Fprintf(stderr, "unable to route!\n"); } /*--------------------------------------------------------------*/ /* next_route_setup -- */ /* */ /*--------------------------------------------------------------*/ int next_route_setup(struct routeinfo_ *iroute, u_char stage) { ROUTE rt; NODE node; POINT gpoint; int i, j; int rval, result; if (iroute->do_pwrbus == TRUE) { iroute->pwrbus_src++; iroute->nsrc = iroute->nsrc->next; rval = -2; while (rval == -2) { if ((iroute->pwrbus_src > iroute->net->numnodes) || (iroute->nsrc == NULL)) { result = 0; break; } else { result = set_powerbus_to_net(iroute->nsrc->netnum); clear_target_node(iroute->nsrc); rval = set_node_to_net(iroute->nsrc, PR_SOURCE, &iroute->glist, &iroute->bbox, stage); if (rval == -2) { if (forceRoutable) { make_routable(iroute->nsrc); } else { iroute->pwrbus_src++; iroute->nsrc = iroute->nsrc->next; } unable_to_route(iroute->net->netname, iroute->nsrc, forceRoutable); } else if (rval < 0) return -1; } } } else { for (rt = iroute->net->routes; (rt && rt->next); rt = rt->next); // Set positions on last route to PR_SOURCE if (rt) { result = set_route_to_net(iroute->net, rt, PR_SOURCE, &iroute->glist, &iroute->bbox, stage); if (result == -2) { unable_to_route(iroute->net->netname, NULL, 0); return -1; } } else return -1; result = (count_targets(iroute->net) == 0) ? 0 : 1; } // Check for the possibility that there is already a route to the target if (!result) { // Remove nodes of the net from Nodeloc so that they will not be // used for crossover costing of future routes. for (i = 0; i < Pinlayers; i++) { for (j = 0; j < NumChannelsX[i] * NumChannelsY[i]; j++) { node = Nodeloc[i][j]; if (node != (NODE)NULL) if (node->netnum == iroute->net->netnum) Nodeloc[i][j] = (NODE)NULL; } } while (iroute->glist) { gpoint = iroute->glist; iroute->glist = iroute->glist->next; free(gpoint); } return 0; } if (!iroute->do_pwrbus) { // If any target is found during the search, but is not the // target that is chosen for the minimum-cost path, then it // will be left marked "processed" and never visited again. // Make sure this doesn't happen my clearing the "processed" // flag from all such target nodes, and placing the positions // on the stack for processing again. clear_non_source_targets(iroute->net, &iroute->glist); } if (Verbose > 1) { Fprintf(stdout, "netname = %s, route number %d\n", iroute->net->netname, TotalRoutes ); Flush(stdout); } if (iroute->maxcost > 2) iroute->maxcost >>= 1; // Halve the maximum cost from the last run return 1; // Successful setup } /*--------------------------------------------------------------*/ /* route_setup -- */ /* */ /*--------------------------------------------------------------*/ int route_setup(struct routeinfo_ *iroute, u_char stage) { POINT gpoint; int i, j; u_int netnum, dir; int result, rval, unroutable; NODE node; PROUTE *Pr; // Make Obs2[][] a copy of Obs[][]. Convert pin obstructions to // terminal positions for the net being routed. for (i = 0; i < Num_layers; i++) { for (j = 0; j < NumChannelsX[i] * NumChannelsY[i]; j++) { netnum = Obs[i][j] & (~BLOCKED_MASK); Pr = &Obs2[i][j]; if (netnum != 0) { Pr->flags = 0; // Clear all flags if (netnum == DRC_BLOCKAGE) Pr->prdata.net = netnum; else Pr->prdata.net = netnum & NETNUM_MASK; dir = netnum & PINOBSTRUCTMASK; if ((dir != 0) && ((dir & STUBROUTE_X) == STUBROUTE_X)) { if ((netnum & NETNUM_MASK) == iroute->net->netnum) Pr->prdata.net = 0; // STUBROUTE_X not routable } } else { Pr->flags = PR_COST; // This location is routable Pr->prdata.cost = MAXRT; } } } if (iroute->net->netnum == VDD_NET || iroute->net->netnum == GND_NET) { // The normal method of selecting source and target is not amenable // to power bus routes. Instead, we use the global standard cell // power rails as the target, and each net in sequence becomes the // sole source node iroute->do_pwrbus = TRUE; iroute->nsrc = find_unrouted_node(iroute->net); result = (iroute->nsrc == NULL) ? 0 : 1; } else { iroute->do_pwrbus = FALSE; if (iroute->net->netnodes != NULL) iroute->nsrc = iroute->net->netnodes; else { Fprintf(stderr, "Net %s has no nodes, unable to route!\n", iroute->net->netname); return -1; } result = 1; } // We start at the node referenced by the route structure, and flag all // of its taps as PR_SOURCE, as well as all connected routes. unroutable = 0; if (result) { iroute->bbox.x2 = iroute->bbox.y2 = 0; iroute->bbox.x1 = NumChannelsX[0]; iroute->bbox.y1 = NumChannelsY[0]; while(1) { rval = set_node_to_net(iroute->nsrc, PR_SOURCE, &iroute->glist, &iroute->bbox, stage); if (rval == -2) { iroute->nsrc = iroute->nsrc->next; if (iroute->nsrc == NULL) break; } else break; } if (rval == -2) { if (forceRoutable) make_routable(iroute->net->netnodes); unable_to_route(iroute->net->netname, iroute->nsrc, forceRoutable); return -1; } if (iroute->do_pwrbus == FALSE) { // Set associated routes to PR_SOURCE rval = set_routes_to_net(iroute->net, PR_SOURCE, &iroute->glist, &iroute->bbox, stage); if (rval == -2) { unable_to_route(iroute->net->netname, NULL, 0); return -1; } // Now search for all other nodes on the same net that have not // yet been routed, and flag all of their taps as PR_TARGET result = 0; for (node = iroute->net->netnodes; node; node = node->next) { if (node == iroute->nsrc) continue; rval = set_node_to_net(node, PR_TARGET, NULL, &iroute->bbox, stage); if (rval == 0) { result = 1; } else if (rval == -2) { if (forceRoutable) make_routable(node); unable_to_route(iroute->net->netname, node, forceRoutable); if (result == 0) result = -1; unroutable++; } } /* If there's only one node and it's not routable, then fail. */ if (result == -1) return -1; } else { /* Do this for power bus connections */ /* Set all nodes that are NOT nsrc to an unused net number */ for (node = iroute->net->netnodes; node; node = node->next) { if (node != iroute->nsrc) { disable_node_nets(node); } } set_powerbus_to_net(iroute->nsrc->netnum); } } // Check for the possibility that there is already a route to the target if (!result) { // Remove nodes of the net from Nodeloc so that they will not be // used for crossover costing of future routes. for (i = 0; i < Pinlayers; i++) { for (j = 0; j < NumChannelsX[i] * NumChannelsY[i]; j++) { iroute->nsrc = Nodeloc[i][j]; if (iroute->nsrc != (NODE)NULL) if (iroute->nsrc->netnum == iroute->net->netnum) Nodeloc[i][j] = (NODE)NULL; } } while (iroute->glist) { gpoint = iroute->glist; iroute->glist = iroute->glist->next; free(gpoint); } return 0; } // Generate a search area mask representing the "likely best route". if ((iroute->do_pwrbus == FALSE) && (maskMode == MASK_AUTO)) { if (stage == 0) createMask(iroute->net, MASK_SMALL, (u_char)Numpasses); else createMask(iroute->net, MASK_LARGE, (u_char)Numpasses); } else if ((iroute->do_pwrbus == TRUE) || (maskMode == MASK_NONE)) fillMask((u_char)0); else if (maskMode == MASK_BBOX) createBboxMask(iroute->net, (u_char)Numpasses); else createMask(iroute->net, maskMode, (u_char)Numpasses); // Heuristic: Set the initial cost beyond which we stop searching. // This value is twice the cost of a direct route across the // maximum extent of the source to target, divided by the square // root of the number of nodes in the net. We purposely set this // value low. It has a severe impact on the total run time of the // algorithm. If the initial max cost is so low that no route can // be found, it will be doubled on each pass. if (iroute->do_pwrbus) iroute->maxcost = 20; // Maybe make this SegCost * row height? else { iroute->maxcost = 1 + 2 * MAX((iroute->bbox.x2 - iroute->bbox.x1), (iroute->bbox.y2 - iroute->bbox.y1)) * SegCost + (int)stage * ConflictCost; iroute->maxcost /= (iroute->nsrc->numnodes - 1); } netnum = iroute->net->netnum; iroute->nsrctap = iroute->nsrc->taps; if (iroute->nsrctap == NULL) iroute->nsrctap = iroute->nsrc->extend; if (iroute->nsrctap == NULL) { unable_to_route(iroute->net->netname, iroute->nsrc, 0); return -1; } if (Verbose > 2) { Fprintf(stdout, "Source node @ %gum %gum layer=%d grid=(%d %d)\n", iroute->nsrctap->x, iroute->nsrctap->y, iroute->nsrctap->layer, iroute->nsrctap->gridx, iroute->nsrctap->gridy); } if (Verbose > 1) { Fprintf(stdout, "netname = %s, route number %d\n", iroute->net->netname, TotalRoutes ); Flush(stdout); } // Successful setup, although if nodes were marked unroutable, // this information is passed back; routing will proceed for // all routable nodes and the net will be then marked as // abandoned. return (unroutable + 1); } /*--------------------------------------------------------------*/ /* route_segs - detailed route from node to node using onestep */ /* method */ /* */ /* ARGS: ROUTE, ready to add segments to do route */ /* RETURNS: NULL if failed, manhattan distance if success */ /* SIDE EFFECTS: */ /* AUTHOR and DATE: steve beccue Fri Aug 8 */ /*--------------------------------------------------------------*/ int route_segs(struct routeinfo_ *iroute, u_char stage, u_char graphdebug) { POINT gpoint, gunproc; SEG seg; int i, j, k, o; int x, y; int pass, maskpass; u_int forbid; GRIDP best, curpt; int result, rval; u_char first = (u_char)1; u_char check_order[6]; u_char max_reached; PROUTE *Pr; best.cost = MAXRT; best.x = 0; best.y = 0; best.lay = 0; gunproc = (POINT)NULL; maskpass = 0; for (pass = 0; pass < Numpasses; pass++) { max_reached = (u_char)0; if (!first && (Verbose > 2)) { Fprintf(stdout, "\n"); first = (u_char)1; } if (Verbose > 2) { Fprintf(stdout, "Pass %d", pass + 1); Fprintf(stdout, " (maxcost is %d)\n", iroute->maxcost); } while (gpoint = iroute->glist) { iroute->glist = gpoint->next; curpt.x = gpoint->x1; curpt.y = gpoint->y1; curpt.lay = gpoint->layer; if (graphdebug) highlight(curpt.x, curpt.y); Pr = &Obs2[curpt.lay][OGRID(curpt.x, curpt.y, curpt.lay)]; // ignore grid positions that have already been processed if (Pr->flags & PR_PROCESSED) { free(gpoint); continue; } if (Pr->flags & PR_COST) curpt.cost = Pr->prdata.cost; // Route points, including target else curpt.cost = 0; // For source tap points // if the grid position is the destination, save the position and // cost if minimum. if (Pr->flags & PR_TARGET) { if (curpt.cost < best.cost) { if (first) { if (Verbose > 2) Fprintf(stdout, "Found a route of cost "); first = (u_char)0; } else if (Verbose > 2) { Fprintf(stdout, "|"); Fprintf(stdout, "%d", curpt.cost); Flush(stdout); } // This position may be on a route, not at a terminal, so // record it. best.x = curpt.x; best.y = curpt.y; best.lay = curpt.lay; best.cost = curpt.cost; // If a complete route has been found, then there's no point // in searching paths with a greater cost than this one. if (best.cost < iroute->maxcost) iroute->maxcost = best.cost; } // Don't continue processing from the target Pr->flags |= PR_PROCESSED; free(gpoint); continue; } if (curpt.cost < MAXRT) { // Severely limit the search space by not processing anything that // is not under the current route mask, which identifies a narrow // "best route" solution. if (RMask[OGRID(curpt.x, curpt.y, 0)] > (u_char)maskpass) { gpoint->next = gunproc; gunproc = gpoint; continue; } // Quick check: Limit maximum cost to limit search space // Move the point onto the "unprocessed" stack and we'll pick up // from this point on the next pass, if needed. if (curpt.cost > iroute->maxcost) { max_reached = (u_char)1; gpoint->next = gunproc; gunproc = gpoint; continue; } } free(gpoint); // check east/west/north/south, and bottom to top // 1st optimization: Direction of route on current layer is preferred. o = LefGetRouteOrientation(curpt.lay); forbid = Obs[curpt.lay][OGRID(curpt.x, curpt.y, curpt.lay)] & BLOCKED_MASK; if (o == 1) { // horizontal routes---check EAST and WEST first check_order[0] = (forbid & BLOCKED_E) ? 0 : EAST; check_order[1] = (forbid & BLOCKED_W) ? 0 : WEST; check_order[2] = (forbid & BLOCKED_U) ? 0 : UP; check_order[3] = (forbid & BLOCKED_D) ? 0 : DOWN; check_order[4] = (forbid & BLOCKED_N) ? 0 : NORTH; check_order[5] = (forbid & BLOCKED_S) ? 0 : SOUTH; } else { // vertical routes---check NORTH and SOUTH first check_order[0] = (forbid & BLOCKED_N) ? 0 : NORTH; check_order[1] = (forbid & BLOCKED_S) ? 0 : SOUTH; check_order[2] = (forbid & BLOCKED_U) ? 0 : UP; check_order[3] = (forbid & BLOCKED_D) ? 0 : DOWN; check_order[4] = (forbid & BLOCKED_E) ? 0 : EAST; check_order[5] = (forbid & BLOCKED_W) ? 0 : WEST; } // Check order is from 0 (1st priority) to 5 (last priority). However, this // is a stack system, so the last one placed on the stack is the first to be // pulled and processed. Therefore we evaluate and drop positions to check // on the stack in reverse order (5 to 0). for (i = 5; i >= 0; i--) { switch (check_order[i]) { case EAST: if ((curpt.x + 1) < NumChannelsX[curpt.lay]) { if ((result = eval_pt(&curpt, PR_PRED_W, stage)) == 1) { gpoint = (POINT)malloc(sizeof(struct point_)); gpoint->x1 = curpt.x + 1; gpoint->y1 = curpt.y; gpoint->layer = curpt.lay; gpoint->next = iroute->glist; iroute->glist = gpoint; } } break; case WEST: if ((curpt.x - 1) >= 0) { if ((result = eval_pt(&curpt, PR_PRED_E, stage)) == 1) { gpoint = (POINT)malloc(sizeof(struct point_)); gpoint->x1 = curpt.x - 1; gpoint->y1 = curpt.y; gpoint->layer = curpt.lay; gpoint->next = iroute->glist; iroute->glist = gpoint; } } break; case SOUTH: if ((curpt.y - 1) >= 0) { if ((result = eval_pt(&curpt, PR_PRED_N, stage)) == 1) { gpoint = (POINT)malloc(sizeof(struct point_)); gpoint->x1 = curpt.x; gpoint->y1 = curpt.y - 1; gpoint->layer = curpt.lay; gpoint->next = iroute->glist; iroute->glist = gpoint; } } break; case NORTH: if ((curpt.y + 1) < NumChannelsY[curpt.lay]) { if ((result = eval_pt(&curpt, PR_PRED_S, stage)) == 1) { gpoint = (POINT)malloc(sizeof(struct point_)); gpoint->x1 = curpt.x; gpoint->y1 = curpt.y + 1; gpoint->layer = curpt.lay; gpoint->next = iroute->glist; iroute->glist = gpoint; } } break; case DOWN: if (curpt.lay > 0) { if ((result = eval_pt(&curpt, PR_PRED_U, stage)) == 1) { gpoint = (POINT)malloc(sizeof(struct point_)); gpoint->x1 = curpt.x; gpoint->y1 = curpt.y; gpoint->layer = curpt.lay - 1; gpoint->next = iroute->glist; iroute->glist = gpoint; } } break; case UP: if (curpt.lay < (Num_layers - 1)) { if ((result = eval_pt(&curpt, PR_PRED_D, stage)) == 1) { gpoint = (POINT)malloc(sizeof(struct point_)); gpoint->x1 = curpt.x; gpoint->y1 = curpt.y; gpoint->layer = curpt.lay + 1; gpoint->next = iroute->glist; iroute->glist = gpoint; } } break; } } // Mark this node as processed Pr->flags |= PR_PROCESSED; } // while stack is not empty while (iroute->glist) { gpoint = iroute->glist; iroute->glist = iroute->glist->next; free(gpoint); } // If we found a route, save it and return if (best.cost <= iroute->maxcost) { curpt.x = best.x; curpt.y = best.y; curpt.lay = best.lay; if ((rval = commit_proute(iroute->rt, &curpt, stage)) != 1) break; if (Verbose > 2) { Fprintf(stdout, "\nCommit to a route of cost %d\n", best.cost); Fprintf(stdout, "Between positions (%d %d) and (%d %d)\n", best.x, best.y, curpt.x, curpt.y); } goto done; /* route success */ } // Continue loop to next pass if any positions were ignored due to // masking or due to exceeding maxcost. // If the cost of the route exceeded maxcost at one or more locations, // then increase maximum cost for next pass. if (max_reached == (u_char)1) { iroute->maxcost <<= 1; // Cost overflow; we're probably completely hosed long before this. if (iroute->maxcost > MAXRT) break; } else maskpass++; // Increase the mask size if (gunproc == NULL) break; // route failure not due to limiting // search to maxcost or to masking // Regenerate the stack of unprocessed nodes iroute->glist = gunproc; gunproc = NULL; } // pass if (!first && (Verbose > 2)) { Fprintf(stdout, "\n"); Flush(stdout); } if (Verbose > 1) { Fprintf(stderr, "Fell through %d passes\n", pass); } if (!iroute->do_pwrbus && (Verbose > 2)) { Fprintf(stderr, "(%g,%g) net=%s\n", iroute->nsrctap->x, iroute->nsrctap->y, iroute->net->netname); } rval = -1; done: // Regenerate the stack of unprocessed nodes iroute->glist = gunproc; gunproc = NULL; return rval; } /* route_segs() */ /*--------------------------------------------------------------*/ /* createemptyroute - begin a ROUTE structure */ /* */ /* ARGS: a nodes */ /* RETURNS: ROUTE calloc'd and ready to begin */ /* SIDE EFFECTS: */ /* AUTHOR and DATE: steve beccue Fri Aug 8 */ /*--------------------------------------------------------------*/ ROUTE createemptyroute() { ROUTE rt; rt = (ROUTE)calloc(1, sizeof(struct route_)); rt->netnum = 0; rt->segments = (SEG)NULL; rt->flags = (u_char)0; rt->next = (ROUTE)NULL; return rt; } /* createemptyroute() */ /*--------------------------------------------------------------*/ /* cleanup_net -- */ /* */ /* Special handling for layers where needblock[] is non-zero, */ /* and shows that two vias cannot be placed on adjacent routes. */ /* emit_routed_net() will add specialnets to merge two adjacent */ /* vias on the same route. However, this cannot be used for */ /* adjacent vias that are each in a different route record. It */ /* is easier just to find any such instances and remove them by */ /* eliminating one of the vias and adding a segment to connect */ /* the route to the neighboring via. */ /*--------------------------------------------------------------*/ void cleanup_net(NET net) { SEG segf, segl, seg; ROUTE rt, rt2; int ls, lf, ll, layer, lastrlayer, lastlayer; u_char fcheck, lcheck, fixed; u_char xcheck, ycheck; for (layer = 0; layer < Num_layers; layer++) { xcheck = needblock[layer] & VIABLOCKX; ycheck = needblock[layer] & VIABLOCKY; if (xcheck || ycheck) { for (rt = net->routes; rt; rt = rt->next) { fixed = FALSE; fcheck = lcheck = FALSE; /* This problem will only show up on route endpoints */ // segf is the first segment of the route. // segl is the last segment of the route. segf = rt->segments; if (segf == NULL) continue; lastlayer = -1; for (segl = segf->next; segl && segl->next; segl = segl->next) if (segl->segtype != ST_VIA) lastlayer = segl->layer; // Set flag fcheck if segf needs checking, and set flag // lcheck if segl needs checking. if (segf->segtype & ST_VIA) { lf = segf->layer; fcheck = (lf != layer && lf != layer - 1) ? FALSE : TRUE; // We're going to remove the contact so it can't be a tap if ((lf < Pinlayers) && (Nodesav[lf][OGRID(segf->x1, segf->y1, lf)] != NULL)) fcheck = FALSE; } if (segl && (segl->segtype & ST_VIA)) { ll = segl->layer; lcheck = (ll != layer && ll != layer - 1) ? FALSE : TRUE; // We're going to remove the contact so it can't be a tap if ((ll < Pinlayers) && (Nodesav[ll][OGRID(segl->x1, segl->y1, ll)] != NULL)) lcheck = FALSE; } if (fcheck == FALSE && lcheck == FALSE) continue; // For each route rt2 that is not rt, look at every via // and see if it is adjacent to segf or segl. for (rt2 = net->routes; rt2; rt2 = rt2->next) { if (rt2 == rt) continue; lastrlayer = -1; for (seg = rt2->segments; seg; seg = seg->next) { if (seg->segtype & ST_VIA) { ls = seg->layer; if (ls != layer && ls != layer - 1) continue; if (fcheck) { if ((ABSDIFF(seg->x1, segf->x1) == 1) && (seg->y1 == segf->y1) && xcheck) { if (ls != lf) { // NOTE: This is still an error, and we should // deal with it by creating a special net. SEG newseg; newseg = (SEG)malloc(sizeof(struct seg_)); rt->segments = newseg; newseg->next = segf; newseg->layer = ll; newseg->segtype = ST_WIRE; newseg->x1 = segf->x1; newseg->y1 = segf->y1; newseg->x2 = seg->x1; newseg->y2 = seg->y1; continue; } segf->segtype = ST_WIRE; segf->x1 = seg->x1; fixed = TRUE; break; } else if ((ABSDIFF(seg->y1, segf->y1) == 1) && (seg->x1 == segf->x1) && ycheck) { if (ls != lf) { // NOTE: This is still an error, and we should // deal with it by creating a special net. SEG newseg; newseg = (SEG)malloc(sizeof(struct seg_)); rt->segments = newseg; newseg->next = segf; newseg->layer = ll; newseg->segtype = ST_WIRE; newseg->x1 = segf->x1; newseg->y1 = segf->y1; newseg->x2 = seg->x1; newseg->y2 = seg->y1; continue; } segf->segtype = ST_WIRE; segf->y1 = seg->y1; fixed = TRUE; break; } } if (lcheck) { if ((ABSDIFF(seg->x1, segl->x1) == 1) && (seg->y1 == segl->y1) && xcheck) { if (ls != ll) { // NOTE: This is still an error, and we should // deal with it by creating a special net. SEG newseg; newseg = (SEG)malloc(sizeof(struct seg_)); segl->next = newseg; newseg->next = NULL; newseg->layer = ll; newseg->segtype = ST_WIRE; newseg->x1 = segl->x1; newseg->y1 = segl->y1; newseg->x2 = seg->x1; newseg->y2 = seg->y1; continue; } else if (lastrlayer < lastlayer) { seg->segtype = ST_WIRE; seg->x2 = segl->x2; } else { segl->segtype = ST_WIRE; segl->x2 = seg->x2; } fixed = TRUE; break; } else if ((ABSDIFF(seg->y1, segl->y1) == 1) && (seg->x1 == segl->x1) && ycheck) { if (ls != ll) { // NOTE: This is still an error, and we should // deal with it by creating a special net. SEG newseg; newseg = (SEG)malloc(sizeof(struct seg_)); segl->next = newseg; newseg->next = NULL; newseg->layer = ll; newseg->segtype = ST_WIRE; newseg->x1 = segl->x1; newseg->y1 = segl->y1; newseg->x2 = seg->x1; newseg->y2 = seg->y1; continue; } else if (lastrlayer < lastlayer) { seg->segtype = ST_WIRE; seg->y2 = segl->y2; } else { segl->segtype = ST_WIRE; segl->y2 = seg->y2; } fixed = TRUE; break; } } } else { lastrlayer = seg->layer; } } if (fixed) break; } } } } } /*--------------------------------------------------------------*/ /* emit_routed_net -- */ /* */ /* Core part of emit_routes(). Dumps the DEF format for a */ /* complete net route to file Cmd. If "special" is TRUE, then */ /* it looks only for stub routes between a grid point and an */ /* off-grid terminal, and dumps only the stub route geometry as */ /* a SPECIALNET, which takes a width parameter. This allows */ /* the stub routes to be given the same width as a via, when */ /* the via is larger than a route width, to avoid DRC notch */ /* errors between the via and the terminal. The SPECIALNETS */ /* are redundant; all routing information is in the NETS */ /* section. The SPECIALNETS only specify a wider route for the */ /* stub connection. */ /*--------------------------------------------------------------*/ void emit_routed_net(FILE *Cmd, NET net, u_char special, double oscale, int iscale) { SEG seg, saveseg, lastseg, prevseg; ROUTE rt; u_int dir1, dir2, tdir; int i, layer; int x, y, x2, y2; double dc; int lastx, lasty, lastlay; int horizontal; DPOINT dp1, dp2; float offset1, offset2; u_char cancel, segtype; double invscale = (double)(1.0 / (double)iscale); /* If the STUB flag is set, then we need to write out the net name */ /* in the SPECIALNETS section. */ if ((special == (u_char)1) && (net->flags & NET_STUB)) { fprintf(Cmd, ";\n- %s\n", net->netname); } int viaOffsetX[MAX_LAYERS][2]; int viaOffsetY[MAX_LAYERS][2]; /* Compute via offsets, if needed for adjacent vias */ for (layer = 0; layer < Num_layers - 1; layer++) { dc = LefGetRouteSpacing(layer) + LefGetViaWidth(layer, layer, 1) - PitchY[layer] - EPS; viaOffsetY[layer][0] = (dc > 0.0) ? (int)((oscale * dc * 0.5) + 0.5) : 0; dc = LefGetRouteSpacing(layer) + LefGetViaWidth(layer, layer, 0) - PitchX[layer] - EPS; viaOffsetX[layer][0] = (dc > 0.0) ? (int)((oscale * dc * 0.5) + 0.5) : 0; dc = LefGetRouteSpacing(layer + 1) + LefGetViaWidth(layer, layer + 1, 1) - PitchY[layer + 1] - EPS; viaOffsetY[layer][1] = (dc > 0.0) ? (int)((oscale * dc * 0.5) + 0.5) : 0; dc = LefGetRouteSpacing(layer + 1) + LefGetViaWidth(layer, layer + 1, 0) - PitchX[layer + 1] - EPS; viaOffsetX[layer][1] = (dc > 0.0) ? (int)((oscale * dc * 0.5) + 0.5) : 0; } Pathon = -1; lastlay = -1; /* Insert routed net here */ for (rt = net->routes; rt; rt = rt->next) { if (rt->segments && !(rt->flags & RT_OUTPUT)) { horizontal = FALSE; cancel = FALSE; // Check first position for terminal offsets seg = (SEG)rt->segments; lastseg = saveseg = seg; layer = seg->layer; if (seg) { // It is rare but possible to have a stub route off of an // endpoint via, so check this case, and use the layer type // of the via top if needed. if ((seg->segtype & ST_VIA) && seg->next && (seg->next->layer <= seg->layer)) layer++; dir1 = Obs[layer][OGRID(seg->x1, seg->y1, layer)]; dir1 &= PINOBSTRUCTMASK; if (dir1 && !(seg->segtype & (ST_OFFSET_START | ST_OFFSET_END))) { if ((special == (u_char)0) && (Verbose > 2)) Fprintf(stdout, "Stub route distance %g to terminal" " at %d %d (%d)\n", Stub[layer][OGRID(seg->x1, seg->y1, layer)], seg->x1, seg->y1, layer); dc = Xlowerbound + (double)seg->x1 * PitchX[layer]; x = (int)((REPS(dc)) * oscale); if (dir1 == STUBROUTE_EW) dc += Stub[layer][OGRID(seg->x1, seg->y1, layer)]; x2 = (int)((REPS(dc)) * oscale); dc = Ylowerbound + (double)seg->y1 * PitchY[layer]; y = (int)((REPS(dc)) * oscale); if (dir1 == STUBROUTE_NS) dc += Stub[layer][OGRID(seg->x1, seg->y1, layer)]; y2 = (int)((REPS(dc)) * oscale); if (dir1 == STUBROUTE_EW) { horizontal = TRUE; // If the gridpoint ahead of the stub has a route // on the same net, and the stub is long enough // to come within a DRC spacing distance of the // other route, then lengthen it to close up the // distance and resolve the error. (NOTE: This // unnecessarily stretches routes to cover taps // that have not been routed to. At least on the // test standard cell set, these rules remove a // handful of DRC errors and don't create any new // ones. If necessary, a flag can be added to // distinguish routes from taps. if ((x < x2) && (seg->x1 < (NumChannelsX[layer] - 1))) { tdir = Obs[layer][OGRID(seg->x1 + 1, seg->y1, layer)]; if ((tdir & ROUTED_NET_MASK) == (net->netnum | ROUTED_NET)) { if (Stub[layer][OGRID(seg->x1, seg->y1, layer)] + LefGetRouteKeepout(layer) >= PitchX[layer]) { dc = Xlowerbound + (double)(seg->x1 + 1) * PitchX[layer]; x2 = (int)((REPS(dc)) * oscale); } } } else if ((x > x2) && (seg->x1 > 0)) { tdir = Obs[layer][OGRID(seg->x1 - 1, seg->y1, layer)]; if ((tdir & ROUTED_NET_MASK) == (net->netnum | ROUTED_NET)) { if (-Stub[layer][OGRID(seg->x1, seg->y1, layer)] + LefGetRouteKeepout(layer) >= PitchX[layer]) { dc = Xlowerbound + (double)(seg->x1 - 1) * PitchX[layer]; x2 = (int)((REPS(dc)) * oscale); } } } dc = oscale * 0.5 * LefGetRouteWidth(layer); if (special == (u_char)0) { // Regular nets include 1/2 route width at // the ends, so subtract from the stub terminus if (x < x2) { x2 -= dc; if (x >= x2) cancel = TRUE; } else { x2 += dc; if (x <= x2) cancel = TRUE; } } else { // Special nets don't include 1/2 route width // at the ends, so add to the route at the grid if (x < x2) x -= dc; else x += dc; // Routes that extend for more than one track // without a bend do not need a wide stub if (seg->x1 != seg->x2) cancel = TRUE; } } else { horizontal = FALSE; // If the gridpoint ahead of the stub has a route // on the same net, and the stub is long enough // to come within a DRC spacing distance of the // other route, then lengthen it to close up the // distance and resolve the error. if ((y < y2) && (seg->y1 < (NumChannelsY[layer] - 1))) { tdir = Obs[layer][OGRID(seg->x1, seg->y1 + 1, layer)]; if ((tdir & ROUTED_NET_MASK) == (net->netnum | ROUTED_NET)) { if (Stub[layer][OGRID(seg->x1, seg->y1, layer)] + LefGetRouteKeepout(layer) >= PitchY[layer]) { dc = Ylowerbound + (double)(seg->y1 + 1) * PitchY[layer]; y2 = (int)((REPS(dc)) * oscale); } } } else if ((y > y2) && (seg->y1 > 0)) { tdir = Obs[layer][OGRID(seg->x1, seg->y1 - 1, layer)]; if ((tdir & ROUTED_NET_MASK) == (net->netnum | ROUTED_NET)) { if (-Stub[layer][OGRID(seg->x1, seg->y1, layer)] + LefGetRouteKeepout(layer) >= PitchY[layer]) { dc = Ylowerbound + (double)(seg->y1 - 1) * PitchY[layer]; y2 = (int)((REPS(dc)) * oscale); } } } dc = oscale * 0.5 * LefGetRouteWidth(layer); if (special == (u_char)0) { // Regular nets include 1/2 route width at // the ends, so subtract from the stub terminus if (y < y2) { y2 -= dc; if (y >= y2) cancel = TRUE; } else { y2 += dc; if (y <= y2) cancel = TRUE; } } else { // Special nets don't include 1/2 route width // at the ends, so add to the route at the grid if (y < y2) y -= dc; else y += dc; // Routes that extend for more than one track // without a bend do not need a wide stub if (seg->y1 != seg->y2) cancel = TRUE; } } if (cancel == FALSE) { net->flags |= NET_STUB; rt->flags |= RT_STUB; pathstart(Cmd, layer, x2, y2, special, oscale, invscale, horizontal); pathto(Cmd, x, y, horizontal, x2, y2, invscale); } lastx = x; lasty = y; lastlay = layer; } } prevseg = NULL; lastseg = NULL; for (seg = rt->segments; seg; seg = seg->next) { layer = seg->layer; // Check for offset terminals at either point offset1 = 0.0; offset2 = 0.0; dir1 = 0; dir2 = 0; if (seg->segtype & ST_OFFSET_START) { dir1 = Obs[seg->layer][OGRID(seg->x1, seg->y1, seg->layer)] & PINOBSTRUCTMASK; if (dir1 == 0 && lastseg) { dir1 = Obs[lastseg->layer][OGRID(lastseg->x2, lastseg->y2, lastseg->layer)] & PINOBSTRUCTMASK; offset1 = Stub[lastseg->layer][OGRID(lastseg->x2, lastseg->y2, lastseg->layer)]; } else offset1 = Stub[seg->layer][OGRID(seg->x1, seg->y1, seg->layer)]; // Offset was calculated for vias; plain metal routes // typically will need less offset distance, so subtract off // the difference. if (!(seg->segtype & ST_VIA)) { if (offset1 < 0) { offset1 += 0.5 * (LefGetViaWidth(seg->layer, seg->layer, horizontal) - LefGetRouteWidth(seg->layer)); if (offset1 > 0) offset1 = 0; } else if (offset1 > 0) { offset1 -= 0.5 * (LefGetViaWidth(seg->layer, seg->layer, horizontal) - LefGetRouteWidth(seg->layer)); if (offset1 < 0) offset1 = 0; } } if (special == (u_char)0) { if ((seg->segtype & ST_VIA) && (Verbose > 2)) Fprintf(stdout, "Offset terminal distance %g to grid" " at %d %d (%d)\n", offset1, seg->x1, seg->y1, layer); } } if (seg->segtype & ST_OFFSET_END) { dir2 = Obs[seg->layer][OGRID(seg->x2, seg->y2, seg->layer)] & PINOBSTRUCTMASK; if (dir2 == 0 && seg->next) { dir2 = Obs[seg->next->layer][OGRID(seg->next->x1, seg->next->y1, seg->next->layer)] & PINOBSTRUCTMASK; offset2 = Stub[seg->next->layer][OGRID(seg->next->x1, seg->next->y1, seg->next->layer)]; } else offset2 = Stub[seg->layer][OGRID(seg->x2, seg->y2, seg->layer)]; // Offset was calculated for vias; plain metal routes // typically will need less offset distance, so subtract off // the difference. if (!(seg->segtype & ST_VIA)) { if (offset2 < 0) { offset2 += 0.5 * (LefGetViaWidth(seg->layer, seg->layer, horizontal) - LefGetRouteWidth(seg->layer)); if (offset2 > 0) offset2 = 0; } else if (offset2 > 0) { offset2 -= 0.5 * (LefGetViaWidth(seg->layer, seg->layer, horizontal) - LefGetRouteWidth(seg->layer)); if (offset2 < 0) offset2 = 0; } } if (special == (u_char)0) { if ((seg->segtype & ST_VIA) && !(seg->segtype & ST_OFFSET_START)) if (Verbose > 2) Fprintf(stdout, "Offset terminal distance %g to grid" " at %d %d (%d)\n", offset2, seg->x2, seg->y2, layer); } } // To do: pick up route layer name from lefInfo. // At the moment, technology names don't even match, // and are redundant between CIFLayer[] from the // config file and lefInfo. dc = Xlowerbound + (double)seg->x1 * PitchX[layer]; if (dir1 == (STUBROUTE_EW | OFFSET_TAP)) dc += offset1; x = (int)((REPS(dc)) * oscale); dc = Ylowerbound + (double)seg->y1 * PitchY[layer]; if (dir1 == (STUBROUTE_NS | OFFSET_TAP)) dc += offset1; y = (int)((REPS(dc)) * oscale); dc = Xlowerbound + (double)seg->x2 * PitchX[layer]; if (dir2 == (STUBROUTE_EW | OFFSET_TAP)) dc += offset2; x2 = (int)((REPS(dc)) * oscale); dc = Ylowerbound + (double)seg->y2 * PitchY[layer]; if (dir2 == (STUBROUTE_NS | OFFSET_TAP)) dc += offset2; y2 = (int)((REPS(dc)) * oscale); segtype = seg->segtype & ~(ST_OFFSET_START | ST_OFFSET_END); switch (segtype) { case ST_WIRE: // Normally layers change only at a via. However, if // a via has been removed and replaced by a 1-track // segment to a neighboring via to avoid DRC errors // (see cleanup_net()), then a layer change may happen // between two ST_WIRE segments, and a new path should // be started. if ((Pathon != -1) && (lastlay != -1) && (lastlay != seg->layer)) Pathon = 0; if (Pathon != 1) { // 1st point of route seg if (x == x2) { horizontal = FALSE; } else if (y == y2) { horizontal = TRUE; } else if (Verbose > 3) { // NOTE: This is a development diagnostic. The // occasional non-Manhanhattan route is due to a // tap offset and is corrected automatically by // making an L-bend in the wire. Flush(stdout); Fprintf(stderr, "Warning: non-Manhattan wire in route" " at (%d %d) to (%d %d)\n", x, y, x2, y2); } if (special == (u_char)0) { pathstart(Cmd, seg->layer, x, y, special, oscale, invscale, horizontal); lastx = x; lasty = y; lastlay = seg->layer; } } rt->flags |= RT_OUTPUT; if (horizontal && x == x2) { horizontal = FALSE; } if ((!horizontal) && y == y2) { horizontal = TRUE; } if (!(x == x2) && !(y == y2)) { horizontal = FALSE; } if (special == (u_char)0) { pathto(Cmd, x2, y2, horizontal, lastx, lasty, invscale); lastx = x2; lasty = y2; } // If a segment is 1 track long, there is a via on either // end, and the needblock flag is set for the layer, then // draw a stub route along the length of the track. if (horizontal && needblock[seg->layer] & VIABLOCKX) { if (ABSDIFF(seg->x2, seg->x1) == 1) { if ((lastseg && lastseg->segtype == ST_VIA) || (seg->next && seg->next->segtype == ST_VIA)) { if (special == (u_char)0) { net->flags |= NET_STUB; rt->flags |= RT_STUB; } else { if (Pathon != -1) Pathon = 0; pathstart(Cmd, layer, x, y, special, oscale, invscale, horizontal); pathto(Cmd, x2, y2, horizontal, x, y, invscale); lastlay = layer; } } } } else if (!horizontal && needblock[seg->layer] & VIABLOCKY) { if (ABSDIFF(seg->y2, seg->y1) == 1) { if ((lastseg && lastseg->segtype == ST_VIA) || (seg->next && seg->next->segtype == ST_VIA)) { if (special == (u_char)0) { net->flags |= NET_STUB; rt->flags |= RT_STUB; } else { if (Pathon != -1) Pathon = 0; pathstart(Cmd, layer, x, y, special, oscale, invscale, horizontal); pathto(Cmd, x2, y2, horizontal, x, y, invscale); lastlay = layer; } } } } break; case ST_VIA: rt->flags |= RT_OUTPUT; if (special == (u_char)0) { if (lastseg == NULL) { // Make sure last position is valid lastx = x; lasty = y; } // Check for vias between adjacent but different nets // that need position offsets to avoid a DRC spacing error if (viaOffsetX[layer][0] > 0) { if (seg->x1 > 0 && ((tdir = (Obs[layer][OGRID(seg->x1 - 1, seg->y1, layer)] & ROUTED_NET_MASK)) != (net->netnum | ROUTED_NET)) && (((tdir & (ROUTED_NET | NO_NET)) == ROUTED_NET))) { pathvia(Cmd, layer, x + viaOffsetX[layer][0], y, lastx, lasty, seg->x1, seg->y1, invscale); } else if ((seg->x1 < NumChannelsX[layer] - 1) && ((tdir = (Obs[layer][OGRID(seg->x1 + 1, seg->y1, layer)] & ROUTED_NET_MASK)) != (net->netnum | ROUTED_NET)) && (((tdir & (ROUTED_NET | NO_NET)) == ROUTED_NET))) { pathvia(Cmd, layer, x - viaOffsetX[layer][0], y, lastx, lasty, seg->x1, seg->y1, invscale); } else pathvia(Cmd, layer, x, y, lastx, lasty, seg->x1, seg->y1, invscale); } else if (viaOffsetY[layer][0] > 0) { if (seg->y1 > 0 && ((tdir = (Obs[layer][OGRID(seg->x1, seg->y1 - 1, layer)] & ROUTED_NET_MASK)) != (net->netnum | ROUTED_NET)) && (((tdir & (ROUTED_NET | NO_NET)) == ROUTED_NET))) { pathvia(Cmd, layer, x, y + viaOffsetY[layer][0], lastx, lasty, seg->x1, seg->y1, invscale); } else if ((seg->y1 < NumChannelsY[layer] - 1) && ((tdir = (Obs[layer][OGRID(seg->x1, seg->y1 + 1, layer)] & ROUTED_NET_MASK)) != (net->netnum | ROUTED_NET)) && (((tdir & (ROUTED_NET | NO_NET)) == ROUTED_NET))) { pathvia(Cmd, layer, x, y - viaOffsetY[layer][0], lastx, lasty, seg->x1, seg->y1, invscale); } else pathvia(Cmd, layer, x, y, lastx, lasty, seg->x1, seg->y1, invscale); } else if (viaOffsetX[layer][1] > 0) { if (seg->x1 > 0 && ((tdir = (Obs[layer + 1][OGRID(seg->x1 - 1, seg->y1, layer + 1)] & ROUTED_NET_MASK)) != (net->netnum | ROUTED_NET)) && (((tdir & (ROUTED_NET | NO_NET)) == ROUTED_NET))) { pathvia(Cmd, layer, x + viaOffsetX[layer][1], y, lastx, lasty, seg->x1, seg->y1, invscale); } else if ((seg->x1 < NumChannelsX[layer + 1] - 1) && ((tdir = (Obs[layer + 1][OGRID(seg->x1 + 1, seg->y1, layer + 1)] & ROUTED_NET_MASK)) != (net->netnum | ROUTED_NET)) && (((tdir & (ROUTED_NET | NO_NET)) == ROUTED_NET))) { pathvia(Cmd, layer, x - viaOffsetX[layer][1], y, lastx, lasty, seg->x1, seg->y1, invscale); } else pathvia(Cmd, layer, x, y, lastx, lasty, seg->x1, seg->y1, invscale); } else if (viaOffsetY[layer][1] > 0) { if (seg->y1 > 0 && ((tdir = (Obs[layer + 1][OGRID(seg->x1, seg->y1 - 1, layer + 1)] & ROUTED_NET_MASK)) != (net->netnum | ROUTED_NET)) && (((tdir & (ROUTED_NET | NO_NET)) == ROUTED_NET))) { pathvia(Cmd, layer, x, y + viaOffsetY[layer][1], lastx, lasty, seg->x1, seg->y1, invscale); } else if ((seg->y1 < NumChannelsY[layer + 1] - 1) && ((tdir = (Obs[layer][OGRID(seg->x1, seg->y1 + 1, layer + 1)] & ROUTED_NET_MASK)) != (net->netnum | ROUTED_NET)) && (((tdir & (ROUTED_NET | NO_NET)) == ROUTED_NET))) { pathvia(Cmd, layer, x, y - viaOffsetY[layer][1], lastx, lasty, seg->x1, seg->y1, invscale); } else pathvia(Cmd, layer, x, y, lastx, lasty, seg->x1, seg->y1, invscale); } else pathvia(Cmd, layer, x, y, lastx, lasty, seg->x1, seg->y1, invscale); lastx = x; lasty = y; lastlay = -1; } break; default: break; } // Break here on last segment so that seg and lastseg are valid // in the following section of code. if (seg->next == NULL) break; prevseg = lastseg; lastseg = seg; } // For stub routes, reset the path between terminals, since // the stubs are not connected. if (special == (u_char)1 && Pathon != -1) Pathon = 0; // Check last position for terminal offsets if (seg && ((seg != saveseg) || (seg->segtype & ST_WIRE))) { cancel = FALSE; layer = seg->layer; dir2 = Obs[layer][OGRID(seg->x2, seg->y2, layer)]; dir2 &= PINOBSTRUCTMASK; if (dir2 && !(seg->segtype & (ST_OFFSET_END | ST_OFFSET_START))) { if ((special == (u_char)0) && (Verbose > 2)) Fprintf(stdout, "Stub route distance %g to terminal" " at %d %d (%d)\n", Stub[layer][OGRID(seg->x2, seg->y2, layer)], seg->x2, seg->y2, layer); dc = Xlowerbound + (double)seg->x2 * PitchX[layer]; x = (int)((REPS(dc)) * oscale); if (dir2 == STUBROUTE_EW) dc += Stub[layer][OGRID(seg->x2, seg->y2, layer)]; x2 = (int)((REPS(dc)) * oscale); dc = Ylowerbound + (double)seg->y2 * PitchY[layer]; y = (int)((REPS(dc)) * oscale); if (dir2 == STUBROUTE_NS) dc += Stub[layer][OGRID(seg->x2, seg->y2, layer)]; y2 = (int)((REPS(dc)) * oscale); if (dir2 == STUBROUTE_EW) { horizontal = TRUE; // If the gridpoint ahead of the stub has a route // on the same net, and the stub is long enough // to come within a DRC spacing distance of the // other route, then lengthen it to close up the // distance and resolve the error. if ((x < x2) && (seg->x2 < (NumChannelsX[layer] - 1))) { tdir = Obs[layer][OGRID(seg->x2 + 1, seg->y2, layer)]; if ((tdir & ROUTED_NET_MASK) == (net->netnum | ROUTED_NET)) { if (Stub[layer][OGRID(seg->x2, seg->y2, layer)] + LefGetRouteKeepout(layer) >= PitchX[layer]) { dc = Xlowerbound + (double)(seg->x2 + 1) * PitchX[layer]; x2 = (int)((REPS(dc)) * oscale); } } } else if ((x > x2) && (seg->x2 > 0)) { tdir = Obs[layer][OGRID(seg->x2 - 1, seg->y2, layer)]; if ((tdir & ROUTED_NET_MASK) == (net->netnum | ROUTED_NET)) { if (-Stub[layer][OGRID(seg->x2, seg->y2, layer)] + LefGetRouteKeepout(layer) >= PitchX[layer]) { dc = Xlowerbound + (double)(seg->x2 - 1) * PitchX[layer]; x2 = (int)((REPS(dc)) * oscale); } } } dc = oscale * 0.5 * LefGetRouteWidth(layer); if (special == (u_char)0) { // Regular nets include 1/2 route width at // the ends, so subtract from the stub terminus if (x < x2) { x2 -= dc; if (x >= x2) cancel = TRUE; } else { x2 += dc; if (x <= x2) cancel = TRUE; } } else { // Special nets don't include 1/2 route width // at the ends, so add to the route at the grid if (x < x2) x -= dc; else x += dc; // Routes that extend for more than one track // without a bend do not need a wide stub if (seg->x1 != seg->x2) cancel = TRUE; } } else { horizontal = FALSE; // If the gridpoint ahead of the stub has a route // on the same net, and the stub is long enough // to come within a DRC spacing distance of the // other route, then lengthen it to close up the // distance and resolve the error. if ((y < y2) && (seg->y2 < (NumChannelsY[layer] - 1))) { tdir = Obs[layer][OGRID(seg->x2, seg->y2 + 1, layer)]; if ((tdir & ROUTED_NET_MASK) == (net->netnum | ROUTED_NET)) { if (Stub[layer][OGRID(seg->x2, seg->y2, layer)] + LefGetRouteKeepout(layer) >= PitchY[layer]) { dc = Ylowerbound + (double)(seg->y2 + 1) * PitchY[layer]; y2 = (int)((REPS(dc)) * oscale); } } } else if ((y > y2) && (seg->y2 > 0)) { tdir = Obs[layer][OGRID(seg->x2, seg->y2 - 1, layer)]; if ((tdir & ROUTED_NET_MASK) == (net->netnum | ROUTED_NET)) { if (-Stub[layer][OGRID(seg->x2, seg->y2, layer)] + LefGetRouteKeepout(layer) >= PitchY[layer]) { dc = Ylowerbound + (double)(seg->y2 - 1) * PitchY[layer]; y2 = (int)((REPS(dc)) * oscale); } } } dc = oscale * 0.5 * LefGetRouteWidth(layer); if (special == (u_char)0) { // Regular nets include 1/2 route width at // the ends, so subtract from the stub terminus if (y < y2) { y2 -= dc; if (y >= y2) cancel = TRUE; } else { y2 += dc; if (y <= y2) cancel = TRUE; } } else { // Special nets don't include 1/2 route width // at the ends, so add to the route at the grid if (y < y2) y -= dc; else y += dc; // Routes that extend for more than one track // without a bend do not need a wide stub if (seg->y1 != seg->y2) cancel = TRUE; } } if (cancel == FALSE) { net->flags |= NET_STUB; rt->flags |= RT_STUB; if (Pathon != 1) { pathstart(Cmd, layer, x, y, special, oscale, invscale, horizontal); lastx = x; lasty = y; } pathto(Cmd, x2, y2, horizontal, lastx, lasty, invscale); lastx = x2; lasty = y2; } } else if (dir2 && (seg->segtype & ST_VIA) && prevseg) { // (seg->segtype & (ST_OFFSET_END | ST_OFFSET_START)) != 0 // is implied. // // Additional handling for offset taps. When a tap position // is a via and is offset in the direction of the last // route segment, then a DRC violation can be created if // (1) the via is wider than the route width, and (2) the // adjacent track position is another via or a bend in the // route, and (3) the tap offset is large enough to create // a spacing violation between the via and the adjacent via // or perpendicular route. If these three conditions are // satisfied, then generate a stub route the width of the // via and one track pitch in length back toward the last // track position. // Problems only arise when the via width is larger than // the width of the metal route leaving the via. if (LefGetViaWidth(seg->layer, lastseg->layer, 1 - horizontal) > LefGetRouteWidth(lastseg->layer)) { // Problems only arise when the last segment is exactly // one track long. if ((ABSDIFF(lastseg->x2, lastseg->x1) == 1) || (ABSDIFF(lastseg->y2, lastseg->y1) == 1)) { if (prevseg->segtype & ST_VIA) { dc = Xlowerbound + (double)seg->x1 * PitchX[layer]; x = (int)((REPS(dc)) * oscale); dc = Ylowerbound + (double)seg->y1 * PitchY[layer]; y = (int)((REPS(dc)) * oscale); dc = Xlowerbound + (double)prevseg->x1 * PitchX[layer]; x2 = (int)((REPS(dc)) * oscale); dc = Ylowerbound + (double)prevseg->y1 * PitchY[layer]; y2 = (int)((REPS(dc)) * oscale); // Setup is (via, 1 track route, via with offset) if (prevseg->x1 != seg->x1) { if ((PitchX[lastseg->layer] - 0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 1) - 0.5 * LefGetViaWidth(prevseg->layer, lastseg->layer, 1) - (prevseg->x1 - seg->x1) * Stub[seg->layer][OGRID(seg->x2, seg->y2, layer)]) < LefGetRouteSpacing(lastseg->layer)) { if (special == (u_char)0) { rt->flags |= RT_STUB; net->flags |= NET_STUB; } else { pathstart(Cmd, lastseg->layer, x, y, (u_char)1, oscale, invscale, 1); pathto(Cmd, x2, y2, 1, x, y, invscale); } } } else if (prevseg->y1 != seg->y1) { if ((PitchY[lastseg->layer] - 0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 0) - 0.5 * LefGetViaWidth(prevseg->layer, lastseg->layer, 0) - (prevseg->y1 - seg->y1) * Stub[seg->layer][OGRID(seg->x2, seg->y2, layer)]) < LefGetRouteSpacing(lastseg->layer)) { if (special == (u_char)0) { rt->flags |= RT_STUB; net->flags |= NET_STUB; } else { pathstart(Cmd, lastseg->layer, x, y, (u_char)1, oscale, invscale, 0); pathto(Cmd, x2, y2, 0, x, y, invscale); } } } } else { // Metal route bends at next track if (prevseg->x1 != seg->x1) { if ((PitchX[lastseg->layer] - 0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 1) - 0.5 * LefGetRouteWidth(prevseg->layer) - (prevseg->x1 - seg->x1) * Stub[seg->layer][OGRID(seg->x2, seg->y2, layer)]) < LefGetRouteSpacing(lastseg->layer)) { if (special == (u_char)0) { rt->flags |= RT_STUB; net->flags |= NET_STUB; } else { pathstart(Cmd, lastseg->layer, x, y, (u_char)1, oscale, invscale, 1); pathto(Cmd, x2, y2, 1, x, y, invscale); } } } else if (prevseg->y1 != seg->y1) { if ((PitchY[lastseg->layer] - 0.5 * LefGetViaWidth(seg->layer, lastseg->layer, 0) - 0.5 * LefGetRouteWidth(prevseg->layer) - (prevseg->y1 - seg->y1) * Stub[seg->layer][OGRID(seg->x2, seg->y2, layer)]) < LefGetRouteSpacing(lastseg->layer)) { if (special == (u_char)0) { rt->flags |= RT_STUB; net->flags |= NET_STUB; } else { pathstart(Cmd, lastseg->layer, x, y, (u_char)1, oscale, invscale, 0); pathto(Cmd, x2, y2, 0, x, y, invscale); } } } } } } } } if (Pathon != -1) Pathon = 0; } // if (rt->segments && !(rt->flags & RT_OUTPUT)) } } /*--------------------------------------------------------------*/ /* emit_routes - DEF file output from the list of routes */ /* */ /* Reads the .def file and rewrites file */ /* _route.def, where each net definition has the */ /* physical route appended. */ /* */ /* ARGS: filename to list to */ /* RETURNS: nothing */ /* SIDE EFFECTS: */ /* AUTHOR and DATE: steve beccue Mon Aug 11 2003 */ /*--------------------------------------------------------------*/ void emit_routes(char *filename, double oscale, int iscale) { FILE *Cmd; int i, j, numnets, stubroutes; char line[MAX_LINE_LEN + 1], *lptr; char netname[MAX_NAME_LEN]; NET net; ROUTE rt; char newDEFfile[256]; FILE *fdef; u_char errcond = FALSE; fdef = fopen(filename, "r"); if (fdef == NULL) { if (strchr(filename, '.') == NULL) { char *extfilename = malloc(strlen(filename) + 5); sprintf(extfilename, "%s.def", filename); fdef = fopen(extfilename, "r"); free(extfilename); } } if (fdef == NULL) { Fprintf(stderr, "emit_routes(): Cannot open DEF file for reading.\n"); return; } if (!strcmp(filename, "stdout")) { Cmd = stdout; } else { char *dotptr; if (filename == DEFfilename) { strcpy(newDEFfile, filename); dotptr = strrchr(newDEFfile, '.'); if (dotptr) strcpy(dotptr, "_route.def"); else strcat(newDEFfile, "_route.def"); Cmd = fopen(newDEFfile, "w"); } else Cmd = fopen(filename, "w"); } if (!Cmd) { Fprintf(stderr, "emit_routes(): Couldn't open output (routed) DEF file.\n"); return; } // Copy DEF file up to NETS line numnets = 0; while (fgets(line, MAX_LINE_LEN, fdef) != NULL) { lptr = line; while (isspace(*lptr)) lptr++; if (!strncmp(lptr, "NETS", 4)) { sscanf(lptr + 4, "%d", &numnets); break; } fputs(line, Cmd); } fputs(line, Cmd); // Write the NETS line // NOTE: May want to remove this message. It may merely reflect // that the DEF file defined one or more SPECIALNETS. if (numnets != Numnets) { Flush(stdout); Fprintf(stderr, "emit_routes(): DEF file has %d nets, but we want" " to write %d\n", numnets, Numnets); } for (i = 0; i < numnets; i++) { if (errcond == TRUE) break; netname[0] == '\0'; while (fgets(line, MAX_LINE_LEN, fdef) != NULL) { if ((lptr = strchr(line, ';')) != NULL) { *lptr = '\n'; *(lptr + 1) = '\0'; break; } else { lptr = line; while (isspace(*lptr)) lptr++; if (*lptr == '-') { lptr++; while (isspace(*lptr)) lptr++; sscanf(lptr, "%s", netname); fputs(line, Cmd); } else if (*lptr == '+') { lptr++; while (isspace(*lptr)) lptr++; if (!strncmp(lptr, "ROUTED", 6)) { // This net is being handled by qrouter, so remove // the original routing information while (fgets(line, MAX_LINE_LEN, fdef) != NULL) { if ((lptr = strchr(line, ';')) != NULL) { *lptr = '\n'; *(lptr + 1) = '\0'; break; } } break; } else fputs(line, Cmd); } else if (!strncmp(lptr, "END", 3)) { // This should not happen fputs(line, Cmd); errcond = TRUE; break; } else fputs(line, Cmd); } } /* Find this net */ for (j = 0; j < Numnets; j++) { net = Nlnets[j]; if (!strcmp(net->netname, netname)) break; } if (!net) { Fprintf(stderr, "emit_routes(): Net %s cannot be found.\n", netname); /* Dump rest of net and continue---no routing information */ *(lptr) = ';'; fputs(line, Cmd); continue; } else { /* Add last net terminal, without the semicolon */ fputs(line, Cmd); cleanup_net(net); emit_routed_net(Cmd, net, (u_char)0, oscale, iscale); fprintf(Cmd, ";\n"); } } // Finish copying the rest of the NETS section if (errcond == FALSE) { while (fgets(line, MAX_LINE_LEN, fdef) != NULL) { lptr = line; while (isspace(*lptr)) lptr++; fputs(line, Cmd); if (!strncmp(lptr, "END", 3)) { break; } } } // Determine how many stub routes we will write to SPECIALNETS // Also reset the OUTPUT flag for each route needing a stubroute // to be written. stubroutes = 0; for (i = 0; i < Numnets; i++) { net = Nlnets[i]; if (net->flags & NET_STUB) { stubroutes++; for (rt = net->routes; rt; rt = rt->next) if (rt->flags & RT_STUB) rt->flags &= ~RT_OUTPUT; } } // If there were stub routes, repeat them in SPECIALNETS at the // proper width. if (stubroutes > 0) { fprintf(Cmd, "\nSPECIALNETS %d ", stubroutes); for (i = 0; i < Numnets; i++) { net = Nlnets[i]; emit_routed_net(Cmd, net, (u_char)1, oscale, iscale); } fprintf(Cmd, ";\nEND SPECIALNETS\n"); } // Finish copying the rest of the file while (fgets(line, MAX_LINE_LEN, fdef) != NULL) { fputs(line, Cmd); } fclose(fdef); fclose(Cmd); } /* emit_routes() */ /*--------------------------------------------------------------*/ /* helpmessage - tell user how to use the program */ /* */ /* ARGS: none. */ /* RETURNS: nothing. */ /* SIDE EFFECTS: */ /* */ /* NOTES: */ /* 1) "qrouter -v0 -h" prints only the version number and exits */ /* 2) Tcl-Tk based version adds ".T" to the end to alert tools */ /* attempting to query the capabilities of qrouter of the */ /* availability of the scripting. */ /* */ /*--------------------------------------------------------------*/ void helpmessage() { if (Verbose > 0) { Fprintf(stdout, "qrouter - maze router by Tim Edwards\n\n"); Fprintf(stdout, "usage: qrouter [-switches] design_name\n\n"); Fprintf(stdout, "switches:\n"); Fprintf(stdout, "\t-c \t\t\tConfiguration file name if not route.cfg.\n"); Fprintf(stdout, "\t-v \t\t\tVerbose output level.\n"); Fprintf(stdout, "\t-i \t\t\tPrint route names and pitches and exit.\n"); Fprintf(stdout, "\t-p \t\t\tSpecify global power bus name.\n"); Fprintf(stdout, "\t-g \t\t\tSpecify global ground bus name.\n"); Fprintf(stdout, "\n"); } #ifdef TCL_QROUTER Fprintf(stdout, "%s.%s.T\n", VERSION, REVISION); #else Fprintf(stdout, "%s.%s\n", VERSION, REVISION); #endif } /* helpmessage() */ /* end of qrouter.c */ qrouter-1.3.33/install-sh0000755000175000001440000001273612406043443014027 0ustar timusers#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 qrouter-1.3.33/qconfig.c0000664000175000001440000003304412616675774013637 0ustar timusers/*--------------------------------------------------------------*/ /* qconfig.c -- .cfg file read/write for route */ /*--------------------------------------------------------------*/ /* Written by Steve Beccue 2003 */ /*--------------------------------------------------------------*/ /* Modified by Tim Edwards, June 2011. The route.cfg file is */ /* no longer the main configuration file but is supplementary */ /* to the LEF and DEF files. Various configuration items that */ /* do not appear in the LEF and DEF formats, such as route */ /* costing, appear in this file, as well as a filename pointer */ /* to the LEF file with information on standard cell macros. */ /*--------------------------------------------------------------*/ #define _GNU_SOURCE // for strcasestr(), see man page #include #include #include #include #include "qrouter.h" #include "qconfig.h" #include "lef.h" int CurrentPin = 0; int Firstcall = TRUE; int PinNumber = 0; int Num_layers = MAX_LAYERS; // layers to use to route double PathWidth[MAX_LAYERS]; // width of the paths int GDSLayer[MAX_LAYERS]; // GDS layer number int GDSCommentLayer = 1; // for dummy wires, etc. char CIFLayer[MAX_LAYERS][50]; // CIF layer name double PitchX[MAX_LAYERS]; // Horizontal wire pitch of layer double PitchY[MAX_LAYERS]; // Vertical wire pitch of layer int NumChannelsX[MAX_LAYERS]; // number of wire channels in X on layer int NumChannelsY[MAX_LAYERS]; // number of wire channels in Y on layer int Vert[MAX_LAYERS]; // 1 if vertical, 0 if horizontal int Numpasses = 10; // number of times to iterate in route_segs char StackedContacts = MAX_LAYERS; // Value is number of contacts that may // be stacked on top of each other. char ViaPattern = VIA_PATTERN_NONE; // Patterning to be used for vias based // on grid position (i.e., checkerboarding) double Xlowerbound=0.0; // Bounding Box of routes, in microns double Xupperbound=0.0; double Ylowerbound=10.0; double Yupperbound=10.0; int SegCost = 1; // Route cost of a segment int ViaCost = 5; // Cost of via between adjacent layers int JogCost = 10; // Cost of 1 grid off-direction jog int XverCost = 4; // Cost of a crossover int BlockCost = 25; // Cost of a crossover when node has // only one tap point int ConflictCost = 50; // Cost of shorting another route // during the rip-up and reroute stage char *ViaX[MAX_LAYERS]; char *ViaY[MAX_LAYERS]; /*--------------------------------------------------------------*/ /* post_config --- */ /* */ /* The following code ensures that the layer grids align. */ /* For now, all PitchX[i] and PitchY[i] should be the same */ /* for all layers. Hopefully this restriction can be lifted */ /* sometime, but it will necessarily be a royal pain. */ /*--------------------------------------------------------------*/ void post_config() { int i, h, v; // Make sure that Num_layers does not exceed the number of // routing layers defined by the LEF file (or the config // file). i = LefGetMaxLayer(); if (i < Num_layers) Num_layers = i; h = v = -1; for (i = 0; i < Num_layers; i++) { if (!Vert[i]) { h = i; PitchY[i] = PitchX[i]; PitchX[i] = 0.0; } else v = i; } // In case all layers are listed as horizontal or all // as vertical, we should still handle it gracefully if (h == -1) h = v; else if (v == -1) v = h; for (i = 0; i < Num_layers; i++) { if (PitchX[i] != 0.0 && PitchX[i] != PitchX[v]) Fprintf(stderr, "Multiple vertical route layers at different" " pitches. I cannot handle this! Using pitch %g\n", PitchX[v]); PitchX[i] = PitchX[v]; if (PitchY[i] != 0.0 && PitchY[i] != PitchY[h]) Fprintf(stderr, "Multiple horizontal route layers at different" " pitches. I cannot handle this! Using pitch %g\n", PitchY[h]); PitchY[i] = PitchY[h]; } } /* post_config() */ /*--------------------------------------------------------------*/ /* read_config - read in the config file */ /* */ /* ARGS: the filename (normally route.cfg) */ /* RETURNS: number of lines successfully read */ /* SIDE EFFECTS: loads Global configuration variables */ /* */ /* "is_info" indicates if qrouter was called with the -i option */ /* in which case the config file read should stop before any */ /* def file is read. */ /*--------------------------------------------------------------*/ int read_config(FILE *fconfig, int is_info) { int count, lines, i, OK; int iarg, iarg2; char carg; double darg, darg2, darg3, darg4; char sarg[MAX_LINE_LEN]; size_t len = 0; char line[MAX_LINE_LEN]; char *lineptr; STRING dnr; // Do Not Route nets STRING cn; // critical nets STRING strl; GATE gateinfo; // gate information, pin location, etc DSEG grect, drect; if (Firstcall) { for (i = 0; i < MAX_LAYERS; i++) { sprintf(line, "via%d%d", i + 1, i + 2); ViaX[i] = strdup(line); ViaY[i] = NULL; } DontRoute = (STRING)NULL; CriticalNet = (STRING)NULL; GateInfo = (GATE)NULL; Nlgates = (GATE)NULL; UserObs = (DSEG)NULL; for (i = 0; i < MAX_LAYERS; i++) PitchX[i] = PitchY[i] = 0.0; Firstcall = 0; } if (!fconfig) return -1; count = 0; lines = 0; while (!feof(fconfig)) { fgets(line, MAX_LINE_LEN, fconfig); lines++; lineptr = line; while (isspace(*lineptr)) lineptr++; if (!strncasecmp(lineptr, "lef", 3) || !strncmp(lineptr, "read_lef", 8)) { if ((i = sscanf(lineptr, "%*s %s\n", sarg)) == 1) { // Argument is a filename of a LEF file from which we // should get the information about gate pins & obstructions OK = 1; LefRead(sarg); } } // The remainder of the statements is not case sensitive. for (i = 0; line[i] && i < MAX_LINE_LEN - 1; i++) { line[i] = (char)tolower(line[i]); } if ((i = sscanf(lineptr, "num_layers %d", &iarg)) == 1) { OK = 1; Num_layers = iarg; } else if ((i = sscanf(lineptr, "layers %d", &iarg)) == 1) { OK = 1; Num_layers = iarg; } if ((i = sscanf(lineptr, "layer_%d_name %s", &iarg2, sarg)) == 2) { if (iarg2 > 0 && iarg2 < 10) { OK = 1; strcpy(CIFLayer[iarg2 - 1], sarg); } } if ((i = sscanf(lineptr, "gds_layer_%d %d", &iarg2, &iarg)) == 2) { if (iarg2 > 0 && iarg2 < 10) { OK = 1; GDSLayer[iarg2 - 1] = iarg; } } if ((i = sscanf(lineptr, "gds_comment_layer %d", &iarg)) == 1) { OK = 1; GDSCommentLayer = iarg; } if ((i = sscanf(lineptr, "layer_1_width %lf", &darg)) == 1) { OK = 1; PathWidth[0] = darg; } if ((i = sscanf(lineptr, "layer_2_width %lf", &darg)) == 1) { OK = 1; PathWidth[1] = darg; } if ((i = sscanf(lineptr, "layer_3_width %lf", &darg)) == 1) { OK = 1; PathWidth[2] = darg; } if ((i = sscanf(lineptr, "layer_4_width %lf", &darg)) == 1) { OK = 1; PathWidth[3] = darg; } if ((i = sscanf(lineptr, "layer_5_width %lf", &darg)) == 1) { OK = 1; PathWidth[4] = darg; } if ((i = sscanf(lineptr, "layer_6_width %lf", &darg)) == 1) { OK = 1; PathWidth[5] = darg; } if ((i = sscanf(lineptr, "layer_7_width %lf", &darg)) == 1) { OK = 1; PathWidth[6] = darg; } if ((i = sscanf(lineptr, "layer_8_width %lf", &darg)) == 1) { OK = 1; PathWidth[7] = darg; } if ((i = sscanf(lineptr, "layer_9_width %lf", &darg)) == 1) { OK = 1; PathWidth[8] = darg; } if ((i = sscanf(lineptr, "x lower bound %lf", &darg)) == 1) { OK = 1; Xlowerbound = darg; } if ((i = sscanf(lineptr, "x upper bound %lf", &darg)) == 1) { OK = 1; Xupperbound = darg; } if ((i = sscanf(lineptr, "y lower bound %lf", &darg)) == 1) { OK = 1; Ylowerbound = darg; } if ((i = sscanf(lineptr, "y upper bound %lf", &darg)) == 1) { OK = 1; Yupperbound = darg; } if ((i = sscanf(lineptr, "layer %d wire pitch %lf\n", &iarg, &darg)) == 2) { OK = 1; PitchX[iarg-1] = darg; } else if (i == 1) { if ((i = sscanf(lineptr, "layer %*d vertical %d\n", &iarg2)) == 1) { OK = 1; Vert[iarg - 1] = iarg2; } else if ((i = sscanf(lineptr, "layer %*d %c\n", &carg)) == 1) { if (tolower(carg) == 'v') { OK = 1; Vert[iarg - 1] = 1; } else if (tolower(carg) == 'h') { OK = 1; Vert[iarg - 1] = 0; } } } if ((i = sscanf(lineptr, "num passes %d\n", &iarg)) == 1) { OK = 1; Numpasses = iarg; } else if ((i = sscanf(lineptr, "passes %d\n", &iarg)) == 1) { OK = 1; Numpasses = iarg; } if ((i = sscanf(lineptr, "route segment cost %d", &iarg)) == 1) { OK = 1; SegCost = iarg; } if ((i = sscanf(lineptr, "route via cost %d", &iarg)) == 1) { OK = 1; ViaCost = iarg; } if ((i = sscanf(lineptr, "route jog cost %d", &iarg)) == 1) { OK = 1; JogCost = iarg; } if ((i = sscanf(lineptr, "route crossover cost %d", &iarg)) == 1) { OK = 1; XverCost = iarg; } if ((i = sscanf(lineptr, "route block cost %d", &iarg)) == 1) { OK = 1; BlockCost = iarg; } if ((i = sscanf(lineptr, "do not route node %s\n", sarg)) == 1) { OK = 1; dnr = (STRING)malloc(sizeof(struct string_)); dnr->name = strdup(sarg); if (DontRoute != NULL) { for (strl = DontRoute; strl->next; strl = strl->next); strl->next = dnr; } else { dnr->next = NULL; DontRoute = dnr; } } if ((i = sscanf(lineptr, "route priority %s\n", sarg)) == 1) { OK = 1; cn = (STRING)malloc(sizeof(struct string_)); cn->name = strdup(sarg); if (CriticalNet != NULL) { for (strl = CriticalNet; strl->next; strl = strl->next); strl->next = cn; } else { cn->next = NULL; CriticalNet = cn; } } if ((i = sscanf(lineptr, "critical net %s\n", sarg)) == 1) { OK = 1; cn = (STRING)malloc(sizeof(struct string_)); cn->name = strdup(sarg); if (CriticalNet != NULL) { for (strl = CriticalNet; strl->next; strl = strl->next); strl->next = cn; } else { cn->next = NULL; CriticalNet = cn; } } // Search for "no stack". This allows variants like "no stacked // contacts", "no stacked vias", or just "no stacking", "no stacks", // etc. if (strcasestr(lineptr, "no stack") != NULL) { OK = 1; StackedContacts = 1; } // Search for "stack N", where "N" is the largest number of vias // that can be stacked upon each other. Values 0 and 1 are both // equivalent to specifying "no stack". if ((i = sscanf(lineptr, "stack %d", &iarg)) == 1) { OK = 1; StackedContacts = iarg; // Can't let StackedContacts be zero because qrouter would // believe that all contacts are disallowed, leading to a // lot of wasted processing time while it determines that's // not possible. . . if (StackedContacts == 0) StackedContacts = 1; } else if ((i = sscanf(lineptr, "via stack %d", &iarg)) == 1) { OK = 1; StackedContacts = iarg; if (StackedContacts == 0) StackedContacts = 1; } // Look for via patterning specifications if (strcasestr(lineptr, "via pattern") != NULL) { if (strcasestr(lineptr + 12, "normal") != NULL) ViaPattern = VIA_PATTERN_NORMAL; else if (strcasestr(lineptr + 12, "invert") != NULL) ViaPattern = VIA_PATTERN_INVERT; } if ((i = sscanf(lineptr, "obstruction %lf %lf %lf %lf %s\n", &darg, &darg2, &darg3, &darg4, sarg)) == 5) { OK = 1; drect = (DSEG)malloc(sizeof(struct dseg_)); drect->x1 = darg; drect->y1 = darg2; drect->x2 = darg3; drect->y2 = darg4; drect->layer = LefFindLayerNum(sarg); if (drect->layer < 0) { if ((i = sscanf(sarg, "%lf", &darg)) == 1) { i = (int)(darg + EPS); if (i >= 0 && i < Num_layers) { drect->layer = i; } } } if (drect->layer >= 0) { drect->next = UserObs; UserObs = drect; } else { free(drect); } } if ((i = sscanf(lineptr, "gate %s %lf %lf\n", sarg, &darg, &darg2)) == 3) { OK = 1; CurrentPin = 0; gateinfo = (GATE)malloc(sizeof(struct gate_)); gateinfo->gatename = strdup(sarg); gateinfo->gatetype = NULL; gateinfo->width = darg; gateinfo->height = darg2; gateinfo->placedX = 0.0; // implicit cell origin gateinfo->placedY = 0.0; gateinfo->next = GateInfo; // prepend to linked gate list GateInfo = gateinfo; } if ((i = sscanf(lineptr, "endgate %s\n", sarg)) == 1) { OK = 1; gateinfo->nodes = CurrentPin; // This syntax does not include declaration of obstructions gateinfo->obs = (DSEG)NULL; CurrentPin = 0; } if ((i = sscanf(lineptr, "pin %s %lf %lf\n", sarg, &darg, &darg2)) == 3) { OK = 1; gateinfo->node[CurrentPin] = strdup(sarg); // These style gates have only one tap per gate; LEF file reader // allows multiple taps per gate node. drect = (DSEG)malloc(sizeof(struct dseg_)); gateinfo->taps[CurrentPin] = drect; drect->x1 = drect->x2 = darg; drect->y1 = drect->y2 = darg2; // This syntax always defines pins on layer 0; LEF file reader // allows pins on all layers. drect->layer = 0; drect->next = (DSEG)NULL; CurrentPin++; } if (OK == 0) { if (!(lineptr[0] == '\n' || lineptr[0] == '#' || lineptr[0] == 0)) { if (!is_info) // Don't report errors on info file generation Fprintf(stderr, "line not understood: %s\n", line); } } OK = 0; line[0] = line[1] = '\0'; } post_config(); return count; } /* read_config() */ qrouter-1.3.33/COPYRIGHT0000644000175000001440000003630712406043443013316 0ustar timusers GNU GENERAL PUBLIC LICENSE Version 2, June 1991 --------------------------------------------------------------------- Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. --------------------------------------------------------------------- Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. --------------------------------------------------------------------- GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) --------------------------------------------------------------------- These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 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 Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. --------------------------------------------------------------------- 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. --------------------------------------------------------------------- 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS qrouter-1.3.33/tkSimple.c0000644000175000001440000003453112406043443013754 0ustar timusers/* *----------------------------------------------------------------------- * tkSimple.c -- * * Implementation of a Very simple window which relies on C code for * almost all of its event handlers. * *----------------------------------------------------------------------- */ #include #include #include void resize(); void expose(); /* Backwards compatibility to tk8.3 and earlier */ #if TK_MAJOR_VERSION == 8 #if TK_MINOR_VERSION <= 3 #define Tk_SetClassProcs(a,b,c) TkSetClassProcs(a,b,c) #endif #endif #ifndef CONST84 #define CONST84 #endif /* * A data structure of the following type is kept for each * simple that currently exists for this process: */ typedef struct { Tk_Window tkwin; /* Window that embodies the simple. NULL * means that the window has been destroyed * but the data structures haven't yet been * cleaned up. */ Display *display; /* Display containing widget. Used, among * other things, so that resources can be * freed even after tkwin has gone away. */ Tcl_Interp *interp; /* Interpreter associated with widget. Used * to delete widget command. */ Tcl_Command widgetCmd; /* Token for simple's widget command. */ char *className; /* Class name for widget (from configuration * option). Malloc-ed. */ int width; /* Width to request for window. <= 0 means * don't request any size. */ int height; /* Height to request for window. <= 0 means * don't request any size. */ char *useThis; /* If the window is embedded, this points to * the name of the window in which it is * embedded (malloc'ed). For non-embedded * windows this is NULL. */ char *exitProc; /* Callback procedure upon window deletion. */ char *mydata; /* This space for hire. */ int flags; /* Various flags; see below for * definitions. */ } Simple; /* * Flag bits for simples: * * GOT_FOCUS: non-zero means this widget currently has the input focus. */ #define GOT_FOCUS 1 static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_PIXELS, "-height", "height", "Height", "0", Tk_Offset(Simple, height), 0}, {TK_CONFIG_PIXELS, "-width", "width", "Width", "0", Tk_Offset(Simple, width), 0}, {TK_CONFIG_STRING, "-use", "use", "Use", "", Tk_Offset(Simple, useThis), TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-exitproc", "exitproc", "ExitProc", "", Tk_Offset(Simple, exitProc), TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-data", "data", "Data", "", Tk_Offset(Simple, mydata), TK_CONFIG_NULL_OK}, {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, 0} }; /* * Forward declarations for procedures defined later in this file: */ static int ConfigureSimple _ANSI_ARGS_((Tcl_Interp *interp, Simple *simplePtr, int objc, Tcl_Obj *CONST objv[], int flags)); static void DestroySimple _ANSI_ARGS_((char *memPtr)); static void SimpleCmdDeletedProc _ANSI_ARGS_(( ClientData clientData)); static void SimpleEventProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); static int SimpleWidgetObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); /* *-------------------------------------------------------------- * * Tk_SimpleObjCmd -- * * This procedure is invoked to process the "simple" * Tcl command. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. These procedures are just wrappers; * they call ButtonCreate to do all of the real work. * *-------------------------------------------------------------- */ int Tk_SimpleObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tk_Window tkwin = (Tk_Window) clientData; Simple *simplePtr; Tk_Window new; char *arg, *useOption; int i, c, depth; size_t length; unsigned int mask; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?"); return TCL_ERROR; } /* * Pre-process the argument list. Scan through it to find any * "-use" option, or the "-main" option. If the "-main" option * is selected, then the application will exit if this window * is deleted. */ useOption = NULL; for (i = 2; i < objc; i += 2) { arg = Tcl_GetStringFromObj(objv[i], (int *) &length); if (length < 2) { continue; } c = arg[1]; if ((c == 'u') && (strncmp(arg, "-use", length) == 0)) { useOption = Tcl_GetString(objv[i+1]); } } /* * Create the window, and deal with the special option -use. */ if (tkwin != NULL) { new = Tk_CreateWindowFromPath(interp, tkwin, Tcl_GetString(objv[1]), NULL); } if (new == NULL) { goto error; } Tk_SetClass(new, "Simple"); if (useOption == NULL) { useOption = (char *)Tk_GetOption(new, "use", "Use"); } if (useOption != NULL) { if (TkpUseWindow(interp, new, useOption) != TCL_OK) { goto error; } } /* * Create the widget record, process configuration options, and * create event handlers. Then fill in a few additional fields * in the widget record from the special options. */ simplePtr = (Simple *) ckalloc(sizeof(Simple)); simplePtr->tkwin = new; simplePtr->display = Tk_Display(new); simplePtr->interp = interp; simplePtr->widgetCmd = Tcl_CreateObjCommand(interp, Tk_PathName(new), SimpleWidgetObjCmd, (ClientData) simplePtr, SimpleCmdDeletedProc); simplePtr->className = NULL; simplePtr->width = 0; simplePtr->height = 0; simplePtr->useThis = NULL; simplePtr->exitProc = NULL; simplePtr->flags = 0; simplePtr->mydata = NULL; /* * Store backreference to simple widget in window structure. */ Tk_SetClassProcs(new, NULL, (ClientData) simplePtr); /* We only handle focus and structure events, and even that might change. */ mask = StructureNotifyMask|FocusChangeMask|NoEventMask; Tk_CreateEventHandler(new, mask, SimpleEventProc, (ClientData) simplePtr); if (ConfigureSimple(interp, simplePtr, objc-2, objv+2, 0) != TCL_OK) { goto error; } Tcl_SetResult(interp, Tk_PathName(new), TCL_STATIC); return TCL_OK; error: if (new != NULL) { Tk_DestroyWindow(new); } return TCL_ERROR; } /* *-------------------------------------------------------------- * * SimpleWidgetObjCmd -- * * This procedure is invoked to process the Tcl command * that corresponds to a simple widget. See the user * documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ static int SimpleWidgetObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Information about simple widget. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { static char *simpleOptions[] = { "cget", "configure", (char *) NULL }; enum options { SIMPLE_CGET, SIMPLE_CONFIGURE }; register Simple *simplePtr = (Simple *) clientData; int result = TCL_OK, index; size_t length; int c, i; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)simpleOptions, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } Tcl_Preserve((ClientData) simplePtr); switch ((enum options) index) { case SIMPLE_CGET: { if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "option"); result = TCL_ERROR; goto done; } result = Tk_ConfigureValue(interp, simplePtr->tkwin, configSpecs, (char *) simplePtr, Tcl_GetString(objv[2]), 0); break; } case SIMPLE_CONFIGURE: { if (objc == 2) { result = Tk_ConfigureInfo(interp, simplePtr->tkwin, configSpecs, (char *) simplePtr, (char *) NULL, 0); } else if (objc == 3) { result = Tk_ConfigureInfo(interp, simplePtr->tkwin, configSpecs, (char *) simplePtr, Tcl_GetString(objv[2]), 0); } else { for (i = 2; i < objc; i++) { char *arg = Tcl_GetStringFromObj(objv[i], (int *) &length); if (length < 2) { continue; } c = arg[1]; if ((c == 'u') && (strncmp(arg, "-use", length) == 0)) { Tcl_AppendResult(interp, "can't modify ", arg, " option after widget is created", (char *) NULL); result = TCL_ERROR; goto done; } } result = ConfigureSimple(interp, simplePtr, objc-2, objv+2, TK_CONFIG_ARGV_ONLY); } break; } } done: Tcl_Release((ClientData) simplePtr); return result; } /* *---------------------------------------------------------------------- * * DestroySimple -- * * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release * to clean up the internal structure of a simple at a safe time * (when no-one is using it anymore). * * Results: * None. * * Side effects: * Everything associated with the simple is freed up. * *---------------------------------------------------------------------- */ static void DestroySimple(memPtr) char *memPtr; /* Info about simple widget. */ { register Simple *simplePtr = (Simple *) memPtr; Tk_FreeOptions(configSpecs, (char *) simplePtr, simplePtr->display, TK_CONFIG_USER_BIT); if (simplePtr->exitProc != NULL) { /* Call the exit procedure */ Tcl_EvalEx(simplePtr->interp, simplePtr->exitProc, -1, 0); } ckfree((char *) simplePtr); } /* *---------------------------------------------------------------------- * * ConfigureSimple -- * * This procedure is called to process an objv/objc list, plus * the Tk option database, in order to configure (or * reconfigure) a simple widget. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then the interp's result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for simplePtr; old resources get freed, if there * were any. * *---------------------------------------------------------------------- */ static int ConfigureSimple(interp, simplePtr, objc, objv, flags) Tcl_Interp *interp; /* Used for error reporting. */ register Simple *simplePtr; /* Information about widget; may or may * not already have values for some fields. */ int objc; /* Number of valid entries in objv. */ Tcl_Obj *CONST objv[]; /* Arguments. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { char *oldMenuName; if (Tk_ConfigureWidget(interp, simplePtr->tkwin, configSpecs, objc, (CONST84 char **) objv, (char *) simplePtr, flags | TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } if ((simplePtr->width > 0) || (simplePtr->height > 0)) { Tk_GeometryRequest(simplePtr->tkwin, simplePtr->width, simplePtr->height); resize(simplePtr->tkwin, simplePtr->width, simplePtr->height); } return TCL_OK; } /* *-------------------------------------------------------------- * * SimpleEventProc -- * * This procedure is invoked by the Tk dispatcher on * structure changes to a simple. For simples with 3D * borders, this procedure is also invoked for exposures. * * Results: * None. * * Side effects: * When the window gets deleted, internal structures get * cleaned up. When it gets exposed, it is redisplayed. * *-------------------------------------------------------------- */ static void SimpleEventProc(clientData, eventPtr) ClientData clientData; /* Information about window. */ register XEvent *eventPtr; /* Information about event. */ { register Simple *simplePtr = (Simple *) clientData; if (eventPtr->type == DestroyNotify) { if (simplePtr->tkwin != NULL) { /* * If this window is a container, then this event could be * coming from the embedded application, in which case * Tk_DestroyWindow hasn't been called yet. When Tk_DestroyWindow * is called later, then another destroy event will be generated. * We need to be sure we ignore the second event, since the simple * could be gone by then. To do so, delete the event handler * explicitly (normally it's done implicitly by Tk_DestroyWindow). */ Tk_DeleteEventHandler(simplePtr->tkwin, StructureNotifyMask | FocusChangeMask, SimpleEventProc, (ClientData) simplePtr); simplePtr->tkwin = NULL; Tcl_DeleteCommandFromToken(simplePtr->interp, simplePtr->widgetCmd); } Tcl_EventuallyFree((ClientData) simplePtr, DestroySimple); } else if (eventPtr->type == FocusIn) { if (eventPtr->xfocus.detail != NotifyInferior) { simplePtr->flags |= GOT_FOCUS; } } else if (eventPtr->type == FocusOut) { if (eventPtr->xfocus.detail != NotifyInferior) { simplePtr->flags &= ~GOT_FOCUS; } } else if (eventPtr->type == ConfigureNotify) { XConfigureEvent *configEventPtr = (XConfigureEvent *)eventPtr; simplePtr->width = configEventPtr->width; simplePtr->height = configEventPtr->height; resize(simplePtr->tkwin, simplePtr->width, simplePtr->height); } else if (eventPtr->type == MapNotify || eventPtr->type == UnmapNotify) { expose(simplePtr->tkwin); } else { fprintf(stderr, "Warning: Event type %d not handled!\n", eventPtr->type); } return; } /* *---------------------------------------------------------------------- * * SimpleCmdDeletedProc -- * * This procedure is invoked when a widget command is deleted. If * the widget isn't already in the process of being destroyed, * this command destroys it. * * Results: * None. * * Side effects: * The widget is destroyed. * *---------------------------------------------------------------------- */ static void SimpleCmdDeletedProc(clientData) ClientData clientData; /* Pointer to widget record for widget. */ { Simple *simplePtr = (Simple *) clientData; Tk_Window tkwin = simplePtr->tkwin; /* * This procedure could be invoked either because the window was * destroyed and the command was then deleted (in which case tkwin * is NULL) or because the command was deleted, and then this procedure * destroys the widget. */ if (tkwin != NULL) { simplePtr->tkwin = NULL; Tk_DestroyWindow(tkwin); } } qrouter-1.3.33/qrouterexec.c0000664000175000001440000000267712607325577014560 0ustar timusers/*----------------------------------------------------------------------*/ /* qrouterexec.c */ /*----------------------------------------------------------------------*/ #include #include #include /*----------------------------------------------------------------------*/ /* Application initiation. This is exactly like the AppInit routine */ /* for "wish", minus the cruft, but with "tcl_rcFileName" set to */ /* "qrouter.tcl" instead of "~/.wishrc". */ /*----------------------------------------------------------------------*/ int qrouter_AppInit(interp) Tcl_Interp *interp; { if (Tcl_Init(interp) == TCL_ERROR) { return TCL_ERROR; } // Ignore Tk_Init return code---maybe can attempt to run in // a non-graphics mode. Tk_Init(interp); Tcl_StaticPackage(interp, "Tk", Tk_Init, Tk_SafeInit); /* This is where we replace the home ".wishrc" file with */ /* qrouter's startup script. */ Tcl_SetVar(interp, "tcl_rcFileName", QROUTER_PATH "/qrouter.tcl", TCL_GLOBAL_ONLY); return TCL_OK; } /*----------------------------------------------------------------------*/ /* The main procedure; replacement for "wish". */ /*----------------------------------------------------------------------*/ int main(argc, argv) int argc; char **argv; { Tk_Main(argc, argv, qrouter_AppInit); return 0; } /*----------------------------------------------------------------------*/ qrouter-1.3.33/maze.c0000664000175000001440000017272712626076247013150 0ustar timusers/*--------------------------------------------------------------*/ /* maze.c -- general purpose maze router routines. */ /* */ /* This file contains the main cost evaluation routine, */ /* the route segment generator, and a routine to search */ /* the database for all parts of a routed network. */ /*--------------------------------------------------------------*/ /* Written by Tim Edwards, June 2011, based on code by Steve */ /* Beccue */ /*--------------------------------------------------------------*/ #include #include #include #define MAZE #include "qrouter.h" #include "qconfig.h" #include "node.h" #include "maze.h" #include "lef.h" extern int TotalRoutes; /*--------------------------------------------------------------*/ /* find_unrouted_node() -- */ /* */ /* On a power bus, the nodes are routed individually, using the */ /* entire power bus as the destination. So to find out if a */ /* node is already routed or not, the only way is to check the */ /* routes recorded for the net and determine if any net */ /* endpoint is on a node. */ /* */ /* Return the first node found that is not connected to any */ /* route endpoint. If all nodes are routed, then return NULL */ /*--------------------------------------------------------------*/ NODE find_unrouted_node(NET net) { int i, numroutes; u_char *routednode; NODE node; ROUTE rt; SEG seg1, seg2; DPOINT tap; // Quick check: If the number of routes == number of nodes, // then return NULL and we're done. numroutes = 0; for (rt = net->routes; rt; rt = rt->next) numroutes++; if (numroutes == net->numnodes) return NULL; routednode = (u_char *)malloc(net->numnodes * sizeof(u_char)); for (i = 0; i < net->numnodes; i++) routednode[i] = 0; // Otherwise, we don't know which nodes have been routed, // so check each one individually. for (rt = net->routes; rt; rt = rt->next) { seg1 = rt->segments; if (seg1 == NULL) continue; seg2 = seg1; while (seg2->next) seg2 = seg2->next; for (node = net->netnodes; node; node = node->next) { if (routednode[node->nodenum] == 1) continue; for (tap = node->taps; tap; tap = tap->next) { if (seg1->x1 == tap->gridx && seg1->y1 == tap->gridy && seg1->layer == tap->layer) { routednode[node->nodenum] = 1; break; } else if (seg1->x2 == tap->gridx && seg1->y2 == tap->gridy && seg1->layer == tap->layer) { routednode[node->nodenum] = 1; break; } else if (seg2->x1 == tap->gridx && seg2->y1 == tap->gridy && seg2->layer == tap->layer) { routednode[node->nodenum] = 1; break; } else if (seg2->x2 == tap->gridx && seg2->y2 == tap->gridy && seg2->layer == tap->layer) { routednode[node->nodenum] = 1; break; } } if (tap == NULL) { for (tap = node->extend; tap; tap = tap->next) { seg1 = rt->segments; seg2 = seg1; while (seg2->next) seg2 = seg2->next; if (seg1->x1 == tap->gridx && seg1->y1 == tap->gridy && seg1->layer == tap->layer) { routednode[node->nodenum] = 1; break; } else if (seg1->x2 == tap->gridx && seg1->y2 == tap->gridy && seg1->layer == tap->layer) { routednode[node->nodenum] = 1; break; } else if (seg2->x1 == tap->gridx && seg2->y1 == tap->gridy && seg2->layer == tap->layer) { routednode[node->nodenum] = 1; break; } else if (seg2->x2 == tap->gridx && seg2->y2 == tap->gridy && seg2->layer == tap->layer) { routednode[node->nodenum] = 1; break; } } } } } for (node = net->netnodes; node; node = node->next) { if (routednode[node->nodenum] == 0) { free(routednode); return node; } } free(routednode); return NULL; /* Statement should never be reached */ } /*--------------------------------------------------------------*/ /* set_powerbus_to_net() */ /* If we have a power or ground net, go through the entire Obs */ /* array and mark all points matching the net as TARGET in Obs2 */ /* */ /* We do this after the call to PR_SOURCE, before the calls */ /* to set PR_TARGET. */ /* */ /* If any grid position was marked as TARGET, return 1, else */ /* return 0 (meaning the net has been routed already). */ /*--------------------------------------------------------------*/ int set_powerbus_to_net(int netnum) { int x, y, lay, rval; PROUTE *Pr; rval = 0; if ((netnum == VDD_NET) || (netnum == GND_NET)) { for (lay = 0; lay < Num_layers; lay++) for (x = 0; x < NumChannelsX[lay]; x++) for (y = 0; y < NumChannelsY[lay]; y++) if ((Obs[lay][OGRID(x, y, lay)] & NETNUM_MASK) == netnum) { Pr = &Obs2[lay][OGRID(x, y, lay)]; // Skip locations that have been purposefully disabled if (!(Pr->flags & PR_COST) && (Pr->prdata.net == MAXNETNUM)) continue; else if (!(Pr->flags & PR_SOURCE)) { Pr->flags |= (PR_TARGET | PR_COST); Pr->prdata.cost = MAXRT; rval = 1; } } } return rval; } /*--------------------------------------------------------------*/ /* clear_non_source_targets -- */ /* */ /* Look at all target nodes of a net. For any that are not */ /* marked as SOURCE, but have terminal points marked as */ /* PROCESSED, remove the PROCESSED flag and put the position */ /* back on the stack for visiting on the next round. */ /*--------------------------------------------------------------*/ void clear_non_source_targets(NET net, POINT *pushlist) { NODE node; DPOINT ntap; PROUTE *Pr; POINT gpoint; int lay, x, y; for (node = net->netnodes; node; node = node->next) { for (ntap = node->taps; ntap; ntap = ntap->next) { lay = ntap->layer; x = ntap->gridx; y = ntap->gridy; Pr = &Obs2[lay][OGRID(x, y, lay)]; if (Pr->flags & PR_TARGET) { if (Pr->flags & PR_PROCESSED) { Pr->flags &= ~PR_PROCESSED; gpoint = (POINT)malloc(sizeof(struct point_)); gpoint->x1 = x; gpoint->y1 = y; gpoint->layer = lay; gpoint->next = *pushlist; *pushlist = gpoint; } } } if (ntap == NULL) { // Try extended tap areas for (ntap = node->extend; ntap; ntap = ntap->next) { lay = ntap->layer; x = ntap->gridx; y = ntap->gridy; Pr = &Obs2[lay][OGRID(x, y, lay)]; if (Pr->flags & PR_TARGET) { if (Pr->flags & PR_PROCESSED) { Pr->flags &= ~PR_PROCESSED; gpoint = (POINT)malloc(sizeof(struct point_)); gpoint->x1 = x; gpoint->y1 = y; gpoint->layer = lay; gpoint->next = *pushlist; *pushlist = gpoint; } } } } } } /*--------------------------------------------------------------*/ /* clear_target_node -- */ /* */ /* Remove PR_TARGET flags from all points belonging to a node */ /*--------------------------------------------------------------*/ int clear_target_node(NODE node) { int x, y, lay; DPOINT ntap; PROUTE *Pr; /* Process tap points of the node */ for (ntap = node->taps; ntap; ntap = ntap->next) { lay = ntap->layer; x = ntap->gridx; y = ntap->gridy; if ((lay < Pinlayers) && (Nodeloc[lay][OGRID(x, y, lay)] == (NODE)NULL)) continue; Pr = &Obs2[lay][OGRID(x, y, lay)]; Pr->flags = 0; Pr->prdata.net = node->netnum; } for (ntap = node->extend; ntap; ntap = ntap->next) { lay = ntap->layer; x = ntap->gridx; y = ntap->gridy; if ((lay < Pinlayers) && Nodesav[lay][OGRID(x, y, lay)] == (NODE)NULL || Nodesav[lay][OGRID(x, y, lay)] != node) continue; Pr = &Obs2[lay][OGRID(x, y, lay)]; Pr->flags = 0; Pr->prdata.net = node->netnum; } } /*--------------------------------------------------------------*/ /* count_targets() --- */ /* */ /* Count the number of nodes of a net that are still marked as */ /* TARGET. */ /*--------------------------------------------------------------*/ int count_targets(NET net) { NODE node; PROUTE *Pr; DPOINT ntap; int lay, x, y; int count = 0; for (node = net->netnodes; node; node = node->next) { for (ntap = node->taps; ntap; ntap = ntap->next) { lay = ntap->layer; x = ntap->gridx; y = ntap->gridy; Pr = &Obs2[lay][OGRID(x, y, lay)]; if (Pr->flags & PR_TARGET) { count++; break; } } if (ntap == NULL) { // Try extended tap areas for (ntap = node->extend; ntap; ntap = ntap->next) { lay = ntap->layer; x = ntap->gridx; y = ntap->gridy; Pr = &Obs2[lay][OGRID(x, y, lay)]; if (Pr->flags & PR_TARGET) { count++; break; } } } } return count; } /*--------------------------------------------------------------*/ /* set_node_to_net() --- */ /* */ /* Change the Obs2[][] flag values to "newflags" for all tap */ /* positions of route terminal "node". Then follow all routes */ /* connected to "node", updating their positions. Where those */ /* routes connect to other nodes, repeat recursively. */ /* */ /* Return value is 1 if at least one terminal of the node */ /* is already marked as PR_SOURCE, indicating that the node */ /* has already been routed. Otherwise, the return value is */ /* zero of no error occured, and -1 if any point was found to */ /* be unoccupied by any net, which should not happen. */ /* */ /* If "bbox" is non-null, record the grid extents of the node */ /* in the x1, x2, y1, y2 values */ /* */ /* If "stage" is 1 (rip-up and reroute), then don't let an */ /* existing route prevent us from adding terminals. However, */ /* the area will be first checked for any part of the terminal */ /* that is routable, only resorting to overwriting colliding */ /* nets if there are no other available taps. Defcon stage 3 */ /* indicates desperation due to a complete lack of routable */ /* taps. This happens if, for example, a port is offset from */ /* the routing grid and tightly boxed in by obstructions. In */ /* such case, we allow routing on an obstruction, but flag the */ /* point. In the output stage, the stub route information will */ /* be used to reposition the contact on the port and away from */ /* the obstruction. */ /* */ /* If we completely fail to find a tap point under any */ /* condition, then return -2. This is a fatal error; there */ /* will be no way to route the net. */ /*--------------------------------------------------------------*/ int set_node_to_net(NODE node, int newflags, POINT *pushlist, SEG bbox, u_char stage) { int x, y, lay, k, obsnet = 0; int result = 0; u_char found_one = (u_char)0; POINT gpoint; DPOINT ntap; PROUTE *Pr; /* If called from set_routes_to_net, the node has no taps, and the */ /* net is a power bus, just return. */ if ((node->taps == NULL) && (node->extend == NULL)) { if ((node->netnum == VDD_NET) || (node->netnum == GND_NET)) return result; } /* Process tap points of the node */ for (ntap = node->taps; ntap; ntap = ntap->next) { lay = ntap->layer; x = ntap->gridx; y = ntap->gridy; Pr = &Obs2[lay][OGRID(x, y, lay)]; if ((Pr->flags & (newflags | PR_COST)) == PR_COST) { Fprintf(stderr, "Error: Tap position %d, %d layer %d not " "marked as source!\n", x, y, lay); return -1; // This should not happen. } if (Pr->flags & PR_SOURCE) { result = 1; // Node is already connected! } else if (((Pr->prdata.net == node->netnum) || (stage == (u_char)2)) && !(Pr->flags & newflags)) { // If we got here, we're on the rip-up stage, and there // is an existing route completely blocking the terminal. // So we will route over it and flag it as a collision. if (Pr->prdata.net != node->netnum) { if ((Pr->prdata.net == (NO_NET | OBSTRUCT_MASK)) || (Pr->prdata.net == NO_NET)) continue; else Pr->flags |= PR_CONFLICT; } // Do the source and dest nodes need to be marked routable? Pr->flags |= (newflags == PR_SOURCE) ? newflags : (newflags | PR_COST); Pr->prdata.cost = (newflags == PR_SOURCE) ? 0 : MAXRT; // push this point on the stack to process if (pushlist != NULL) { gpoint = (POINT)malloc(sizeof(struct point_)); gpoint->x1 = x; gpoint->y1 = y; gpoint->layer = lay; gpoint->next = *pushlist; *pushlist = gpoint; } found_one = (u_char)1; // record extents if (bbox) { if (x < bbox->x1) bbox->x1 = x; if (x > bbox->x2) bbox->x2 = x; if (y < bbox->y1) bbox->y1 = y; if (y > bbox->y2) bbox->y2 = y; } } else if ((Pr->prdata.net < MAXNETNUM) && (Pr->prdata.net > 0)) obsnet++; } // Do the same for point in the halo around the tap, but only if // they have been attached to the net during a past routing run. for (ntap = node->extend; ntap; ntap = ntap->next) { lay = ntap->layer; x = ntap->gridx; y = ntap->gridy; // Don't process extended areas if they coincide with other nodes. if ((lay < Pinlayers) && (Nodesav[lay][OGRID(x, y, lay)] == (NODE)NULL || Nodesav[lay][OGRID(x, y, lay)] != node)) continue; Pr = &Obs2[lay][OGRID(x, y, lay)]; if (Pr->flags & PR_SOURCE) { result = 1; // Node is already connected! } else if ( !(Pr->flags & newflags) && ((Pr->prdata.net == node->netnum) || (stage == (u_char)2 && Pr->prdata.net < MAXNETNUM) || (stage == (u_char)3))) { if (Pr->prdata.net != node->netnum) Pr->flags |= PR_CONFLICT; Pr->flags |= (newflags == PR_SOURCE) ? newflags : (newflags | PR_COST); Pr->prdata.cost = (newflags == PR_SOURCE) ? 0 : MAXRT; // push this point on the stack to process if (pushlist != NULL) { gpoint = (POINT)malloc(sizeof(struct point_)); gpoint->x1 = x; gpoint->y1 = y; gpoint->layer = lay; gpoint->next = *pushlist; *pushlist = gpoint; } found_one = (u_char)1; // record extents if (bbox) { if (x < bbox->x1) bbox->x1 = x; if (x > bbox->x2) bbox->x2 = x; if (y < bbox->y1) bbox->y1 = y; if (y > bbox->y2) bbox->y2 = y; } } else if ((Pr->prdata.net < MAXNETNUM) && (Pr->prdata.net > 0)) obsnet++; } // In the case that no valid tap points were found, if we're on the // rip-up and reroute section, try again, ignoring existing routes that // are in the way of the tap point. If that fails, then we will // route over obstructions and shift the contact when committing the // route solution. And if that fails, we're basically hosed. // // Make sure to check for the case that the tap point is simply not // reachable from any grid point, in the first stage, so we don't // wait until the rip-up and reroute stage to route them. if ((result == 0) && (found_one == (u_char)0)) { if (stage == (u_char)1) return set_node_to_net(node, newflags, pushlist, bbox, (u_char)2); else if (stage == (u_char)2) return set_node_to_net(node, newflags, pushlist, bbox, (u_char)3); else if ((stage == (u_char)0) && (obsnet == 0)) return set_node_to_net(node, newflags, pushlist, bbox, (u_char)3); else return -2; } return result; } /*--------------------------------------------------------------*/ /* Set all taps of node "node" to MAXNETNUM, so that it will not */ /* be routed to. */ /*--------------------------------------------------------------*/ int disable_node_nets(NODE node) { int x, y, lay; int result = 0; DPOINT ntap; PROUTE *Pr; /* Process tap points of the node */ for (ntap = node->taps; ntap; ntap = ntap->next) { lay = ntap->layer; x = ntap->gridx; y = ntap->gridy; Pr = &Obs2[lay][OGRID(x, y, lay)]; if (Pr->flags & PR_SOURCE || Pr->flags & PR_TARGET || Pr->flags & PR_COST) { result = 1; } else if (Pr->prdata.net == node->netnum) { Pr->prdata.net = MAXNETNUM; } } // Do the same for point in the halo around the tap, but only if // they have been attached to the net during a past routing run. for (ntap = node->extend; ntap; ntap = ntap->next) { lay = ntap->layer; x = ntap->gridx; y = ntap->gridy; Pr = &Obs2[lay][OGRID(x, y, lay)]; if (Pr->flags & PR_SOURCE || Pr->flags & PR_TARGET || Pr->flags & PR_COST) { result = 1; } else if (Pr->prdata.net == node->netnum) { Pr->prdata.net = MAXNETNUM; } } return result; } /*--------------------------------------------------------------*/ /* That which is already routed (routes should be attached to */ /* source nodes) is routable by definition. . . */ /*--------------------------------------------------------------*/ int set_route_to_net(NET net, ROUTE rt, int newflags, POINT *pushlist, SEG bbox, u_char stage) { int x, y, lay, k; int result = 0; POINT gpoint; SEG seg; NODE n2; PROUTE *Pr; if (rt && rt->segments) { for (seg = rt->segments; seg; seg = seg->next) { lay = seg->layer; x = seg->x1; y = seg->y1; while (1) { Pr = &Obs2[lay][OGRID(x, y, lay)]; Pr->flags = (newflags == PR_SOURCE) ? newflags : (newflags | PR_COST); // Conflicts should not happen (check for this?) // if (Pr->prdata.net != node->netnum) Pr->flags |= PR_CONFLICT; Pr->prdata.cost = (newflags == PR_SOURCE) ? 0 : MAXRT; // push this point on the stack to process if (pushlist != NULL) { gpoint = (POINT)malloc(sizeof(struct point_)); gpoint->x1 = x; gpoint->y1 = y; gpoint->layer = lay; gpoint->next = *pushlist; *pushlist = gpoint; } // record extents if (bbox) { if (x < bbox->x1) bbox->x1 = x; if (x > bbox->x2) bbox->x2 = x; if (y < bbox->y1) bbox->y1 = y; if (y > bbox->y2) bbox->y2 = y; } // If we found another node connected to the route, // then process it, too. n2 = (lay >= Pinlayers) ? NULL : Nodeloc[lay][OGRID(x, y, lay)]; if ((n2 != (NODE)NULL) && (n2 != net->netnodes)) { if (newflags == PR_SOURCE) clear_target_node(n2); result = set_node_to_net(n2, newflags, pushlist, bbox, stage); // On error, continue processing } // Process top part of via if (seg->segtype & ST_VIA) { if (lay != seg->layer) break; lay++; continue; } // Move to next grid position in segment if (x == seg->x2 && y == seg->y2) break; if (seg->x2 > seg->x1) x++; else if (seg->x2 < seg->x1) x--; if (seg->y2 > seg->y1) y++; else if (seg->y2 < seg->y1) y--; } } } return result; } /*--------------------------------------------------------------*/ /* Process all routes of a net, and set their routed positions */ /* to SOURCE in Obs2[] */ /*--------------------------------------------------------------*/ int set_routes_to_net(NET net, int newflags, POINT *pushlist, SEG bbox, u_char stage) { ROUTE rt; int result; for (rt = net->routes; rt; rt = rt->next) result = set_route_to_net(net, rt, newflags, pushlist, bbox, stage); return result; } /*--------------------------------------------------------------*/ /* Used by find_colliding() (see below). Save net "netnum" */ /* to the list of colliding nets if it is not already in the */ /* list. Return 1 if the list got longer, 0 otherwise. */ /*--------------------------------------------------------------*/ int addcollidingnet(NETLIST *nlptr, int netnum) { NETLIST cnl; NET fnet; int i; for (cnl = *nlptr; cnl; cnl = cnl->next) if (cnl->net->netnum == netnum) return 0; for (i = 0; i < Numnets; i++) { fnet = Nlnets[i]; if (fnet->netnum == netnum) { cnl = (NETLIST)malloc(sizeof(struct netlist_)); cnl->net = fnet; cnl->next = *nlptr; *nlptr = cnl; return 1; } } return 0; } /*--------------------------------------------------------------*/ /* Find nets that are colliding with the given net "net", and */ /* create and return a list of them. */ /*--------------------------------------------------------------*/ NETLIST find_colliding(NET net, int *ripnum) { NETLIST nl = (NETLIST)NULL, cnl; ROUTE rt; SEG seg; int lay, i, x, y, orignet, rnum; /* Scan the routed points for recorded collisions. */ rnum = 0; for (rt = net->routes; rt; rt = rt->next) { if (rt->segments) { for (seg = rt->segments; seg; seg = seg->next) { lay = seg->layer; x = seg->x1; y = seg->y1; // The following skips over vias, which is okay, since // those positions are covered by segments on both layers // or are terminal positions that by definition can't // belong to a different net. while (1) { orignet = Obs[lay][OGRID(x, y, lay)] & ROUTED_NET_MASK; if (orignet == DRC_BLOCKAGE) { /* If original position was a DRC-related blockage, */ /* find out which net or nets would be in conflict. */ if (needblock[lay] & (ROUTEBLOCKX | VIABLOCKX)) { if (x < NumChannelsX[lay] - 1) { orignet = Obs[lay][OGRID(x + 1, y, lay)] & ROUTED_NET_MASK; if (!(orignet & NO_NET)) { orignet &= NETNUM_MASK; if ((orignet != 0) && (orignet != net->netnum)) rnum += addcollidingnet(&nl, orignet); } } if (x > 0) { orignet = Obs[lay][OGRID(x - 1, y, lay)] & ROUTED_NET_MASK; if (!(orignet & NO_NET)) { orignet &= NETNUM_MASK; if ((orignet != 0) && (orignet != net->netnum)) rnum += addcollidingnet(&nl, orignet); } } } if (needblock[lay] & (ROUTEBLOCKY | VIABLOCKY)) { if (y < NumChannelsY[lay] - 1) { orignet = Obs[lay][OGRID(x, y + 1, lay)] & ROUTED_NET_MASK; if (!(orignet & NO_NET)) { orignet &= NETNUM_MASK; if ((orignet != 0) && (orignet != net->netnum)) rnum += addcollidingnet(&nl, orignet); } } if (y > 0) { orignet = Obs[lay][OGRID(x, y - 1, lay)] & ROUTED_NET_MASK; if (!(orignet & NO_NET)) { orignet &= NETNUM_MASK; if ((orignet != 0) && (orignet != net->netnum)) rnum += addcollidingnet(&nl, orignet); } } } } else if ((orignet & NETNUM_MASK) != net->netnum) rnum += addcollidingnet(&nl, (orignet & NETNUM_MASK)); if ((x == seg->x2) && (y == seg->y2)) break; if (x < seg->x2) x++; else if (x > seg->x2) x--; if (y < seg->y2) y++; else if (y > seg->y2) y--; } } } } /* Diagnostic */ if ((nl != NULL) && (Verbose > 0)) { Fprintf(stdout, "Best route of %s collides with nets: ", net->netname); for (cnl = nl; cnl; cnl = cnl->next) { Fprintf(stdout, "%s ", cnl->net->netname); } Fprintf(stdout, "\n"); } if (ripnum) *ripnum = rnum; return nl; } /*--------------------------------------------------------------*/ /* ripup_net --- */ /* */ /* Rip up the entire network located at position x, y, lay. */ /* */ /* If argument "restore" is TRUE, then at each node, restore */ /* the crossover cost by attaching the node back to the Nodeloc */ /* array. */ /*--------------------------------------------------------------*/ u_char ripup_net(NET net, u_char restore) { int thisnet, oldnet, x, y, lay, dir; double sreq; NODE node; ROUTE rt; SEG seg; DPOINT ntap; thisnet = net->netnum; for (rt = net->routes; rt; rt = rt->next) { if (rt->segments) { for (seg = rt->segments; seg; seg = seg->next) { lay = seg->layer; x = seg->x1; y = seg->y1; while (1) { oldnet = Obs[lay][OGRID(x, y, lay)] & NETNUM_MASK; if ((oldnet > 0) && (oldnet < MAXNETNUM)) { if (oldnet != thisnet) { Fprintf(stderr, "Error: position %d %d layer %d has net " "%d not %d!\n", x, y, lay, oldnet, thisnet); return FALSE; // Something went wrong } // Reset the net number to zero along this route for // every point that is not a node tap. Points that // were routed over obstructions to reach off-grid // taps are returned to obstructions. if ((lay >= Pinlayers) || Nodesav[lay][OGRID(x, y, lay)] == (NODE)NULL) { dir = Obs[lay][OGRID(x, y, lay)] & PINOBSTRUCTMASK; if (dir == 0) Obs[lay][OGRID(x, y, lay)] = 0; else Obs[lay][OGRID(x, y, lay)] = NO_NET | dir; } else { // Clear routed mask bit Obs[lay][OGRID(x, y, lay)] &= ~ROUTED_NET; } // Routes which had blockages added on the sides due // to spacing constraints have DRC_BLOCKAGE set; // these flags should be removed. if (needblock[lay] & (ROUTEBLOCKX | VIABLOCKX)) { if ((x > 0) && ((Obs[lay][OGRID(x - 1, y, lay)] & DRC_BLOCKAGE) == DRC_BLOCKAGE)) Obs[lay][OGRID(x - 1, y, lay)] &= ~DRC_BLOCKAGE; else if ((x < NumChannelsX[lay] - 1) && ((Obs[lay][OGRID(x + 1, y, lay)] & DRC_BLOCKAGE) == DRC_BLOCKAGE)) Obs[lay][OGRID(x + 1, y, lay)] &= ~DRC_BLOCKAGE; } if (needblock[lay] & (ROUTEBLOCKY | VIABLOCKY)) { if ((y > 0) && ((Obs[lay][OGRID(x, y - 1, lay)] & DRC_BLOCKAGE) == DRC_BLOCKAGE)) Obs[lay][OGRID(x, y - 1, lay)] &= ~DRC_BLOCKAGE; else if ((y < NumChannelsY[lay] - 1) && ((Obs[lay][OGRID(x, y + 1, lay)] & DRC_BLOCKAGE) == DRC_BLOCKAGE)) Obs[lay][OGRID(x, y + 1, lay)] &= ~DRC_BLOCKAGE; } } // This break condition misses via ends, but those are // terminals and don't get ripped out. if ((x == seg->x2) && (y == seg->y2)) break; if (x < seg->x2) x++; else if (x > seg->x2) x--; if (y < seg->y2) y++; else if (y > seg->y2) y--; } } } } // For each net node tap, restore the node pointer on Nodeloc so // that crossover costs are again applied to routes over this // node tap. if (restore != 0) { for (node = net->netnodes; node; node = node->next) { for (ntap = node->taps; ntap; ntap = ntap->next) { lay = ntap->layer; x = ntap->gridx; y = ntap->gridy; if (lay < Pinlayers) Nodeloc[lay][OGRID(x, y, lay)] = Nodesav[lay][OGRID(x, y, lay)]; } } } /* Remove all routing information from this net */ while (net->routes) { rt = net->routes; net->routes = rt->next; while (rt->segments) { seg = rt->segments->next; free(rt->segments); rt->segments = seg; } free(rt); } return TRUE; } /*--------------------------------------------------------------*/ /* eval_pt - evaluate cost to get from given point to */ /* current point. Current point is passed in "ept", and */ /* the direction from the new point to the current point */ /* is indicated by "flags". */ /* */ /* ONLY consider the cost of the single step itself. */ /* */ /* If "stage" is nonzero, then this is a second stage */ /* routing, where we should consider other nets to be a */ /* high cost to short to, rather than a blockage. This */ /* will allow us to finish the route, but with a minimum */ /* number of collisions with other nets. Then, we rip up */ /* those nets, add them to the "failed" stack, and re- */ /* route this one. */ /* */ /* ARGS: none */ /* RETURNS: 1 if node needs to be (re)processed, 0 if not. */ /* SIDE EFFECTS: none (get this right or else) */ /*--------------------------------------------------------------*/ int eval_pt(GRIDP *ept, u_char flags, u_char stage) { int thiscost = 0; int netnum; NODE node; NETLIST nl; PROUTE *Pr, *Pt; GRIDP newpt; newpt = *ept; switch (flags) { case PR_PRED_N: newpt.y--; break; case PR_PRED_S: newpt.y++; break; case PR_PRED_E: newpt.x--; break; case PR_PRED_W: newpt.x++; break; case PR_PRED_U: newpt.lay--; break; case PR_PRED_D: newpt.lay++; break; } Pr = &Obs2[newpt.lay][OGRID(newpt.x, newpt.y, newpt.lay)]; if (!(Pr->flags & (PR_COST | PR_SOURCE))) { // 2nd stage allows routes to cross existing routes netnum = Pr->prdata.net; if (stage && (netnum < MAXNETNUM)) { if ((newpt.lay < Pinlayers) && Nodesav[newpt.lay][OGRID(newpt.x, newpt.y, newpt.lay)] != NULL) return 0; // But cannot route over terminals! // Is net k in the "noripup" list? If so, don't route it */ for (nl = CurNet->noripup; nl; nl = nl->next) { if (nl->net->netnum == netnum) return 0; } // In case of a collision, we change the grid point to be routable // but flag it as a point of collision so we can later see what // were the net numbers of the interfering routes by cross-referencing // the Obs[][] array. Pr->flags |= (PR_CONFLICT | PR_COST); Pr->prdata.cost = MAXRT; thiscost = ConflictCost; } else if (stage && (netnum == DRC_BLOCKAGE)) { if ((newpt.lay < Pinlayers) && Nodesav[newpt.lay][OGRID(newpt.x, newpt.y, newpt.lay)] != NULL) return 0; // But cannot route over terminals! // Position does not contain the net number, so we have to // go looking for it. Fortunately this is a fairly rare // occurrance. But it is necessary to find all neighboring // nets that might have created the blockage, and refuse to // route here if any of them are on the noripup list. if (needblock[newpt.lay] & (ROUTEBLOCKX | VIABLOCKX)) { if (newpt.x < NumChannelsX[newpt.lay] - 1) { netnum = Obs[newpt.lay][OGRID(newpt.x + 1, newpt.y, newpt.lay)] & ROUTED_NET_MASK; if (!(netnum & NO_NET)) { netnum &= NETNUM_MASK; if ((netnum != 0) && (netnum != CurNet->netnum)) // Is net k in the "noripup" list? If so, don't route it */ for (nl = CurNet->noripup; nl; nl = nl->next) if (nl->net->netnum == netnum) return 0; } } if (newpt.x > 0) { netnum = Obs[newpt.lay][OGRID(newpt.x - 1, newpt.y, newpt.lay)] & ROUTED_NET_MASK; if (!(netnum & NO_NET)) { netnum &= NETNUM_MASK; if ((netnum != 0) && (netnum != CurNet->netnum)) // Is net k in the "noripup" list? If so, don't route it */ for (nl = CurNet->noripup; nl; nl = nl->next) if (nl->net->netnum == netnum) return 0; } } } if (needblock[newpt.lay] & (ROUTEBLOCKY | VIABLOCKY)) { if (newpt.y < NumChannelsY[newpt.lay] - 1) { netnum = Obs[newpt.lay][OGRID(newpt.x, newpt.y + 1, newpt.lay)] & ROUTED_NET_MASK; if (!(netnum & NO_NET)) { netnum &= NETNUM_MASK; if ((netnum != 0) && (netnum != CurNet->netnum)) // Is net k in the "noripup" list? If so, don't route it */ for (nl = CurNet->noripup; nl; nl = nl->next) if (nl->net->netnum == netnum) return 0; } } if (newpt.y > 0) { netnum = Obs[newpt.lay][OGRID(newpt.x, newpt.y - 1, newpt.lay)] & ROUTED_NET_MASK; if (!(netnum & NO_NET)) { netnum &= NETNUM_MASK; if ((netnum != 0) && (netnum != CurNet->netnum)) // Is net k in the "noripup" list? If so, don't route it */ for (nl = CurNet->noripup; nl; nl = nl->next) if (nl->net->netnum == netnum) return 0; } } } // In case of a collision, we change the grid point to be routable // but flag it as a point of collision so we can later see what // were the net numbers of the interfering routes by cross-referencing // the Obs[][] array. Pr->flags |= (PR_CONFLICT | PR_COST); Pr->prdata.cost = MAXRT; thiscost = ConflictCost; } else return 0; // Position is not routeable } // Compute the cost to step from the current point to the new point. // "BlockCost" is used if the node has only one point to connect to, // so that routing over it could block it entirely. if ((newpt.lay > 0) && (newpt.lay < Pinlayers)) { if ((node = Nodeloc[newpt.lay - 1][OGRID(newpt.x, newpt.y, newpt.lay - 1)]) != (NODE)NULL) { Pt = &Obs2[newpt.lay - 1][OGRID(newpt.x, newpt.y, newpt.lay - 1)]; if (!(Pt->flags & PR_TARGET) && !(Pt->flags & PR_SOURCE)) { if (node->taps && (node->taps->next == NULL)) thiscost += BlockCost; // Cost to block out a tap else if (node->taps == NULL) { if (node->extend != NULL) { if (node->extend->next == NULL) // Node has only one extended access point: Try // very hard to avoid routing over it thiscost += 10 * BlockCost; else thiscost += BlockCost; } // If both node->taps and node->extend are NULL, then // the node has no access and will never be routed, so // don't bother costing it. } else thiscost += XverCost; // Cross-under cost } } } if (((newpt.lay + 1) < Pinlayers) && (newpt.lay < Num_layers - 1)) { if ((node = Nodeloc[newpt.lay + 1][OGRID(newpt.x, newpt.y, newpt.lay + 1)]) != (NODE)NULL) { Pt = &Obs2[newpt.lay + 1][OGRID(newpt.x, newpt.y, newpt.lay + 1)]; if (!(Pt->flags & PR_TARGET) && !(Pt->flags & PR_SOURCE)) { if (node->taps && (node->taps->next == NULL)) thiscost += BlockCost; // Cost to block out a tap else thiscost += XverCost; // Cross-over cost } } } if (ept->lay != newpt.lay) thiscost += ViaCost; if (ept->x != newpt.x) thiscost += (Vert[newpt.lay] * JogCost + (1 - Vert[newpt.lay]) * SegCost); if (ept->y != newpt.y) thiscost += (Vert[newpt.lay] * SegCost + (1 - Vert[newpt.lay]) * JogCost); // Add the cost to the cost of the original position thiscost += ept->cost; // Replace node information if cost is minimum if (Pr->flags & PR_CONFLICT) thiscost += ConflictCost; // For 2nd stage routes if (thiscost < Pr->prdata.cost) { Pr->flags &= ~PR_PRED_DMASK; Pr->flags |= flags; Pr->prdata.cost = thiscost; Pr->flags &= ~PR_PROCESSED; // Need to reprocess this node if (Verbose > 3) { Fprintf(stdout, "New cost %d at (%d %d %d)\n", thiscost, newpt.x, newpt.y, newpt.lay); } return 1; } return 0; // New position did not get a lower cost } /* eval_pt() */ /*------------------------------------------------------*/ /* writeback_segment() --- */ /* */ /* Copy information from a single segment back */ /* the Obs[] array. */ /* */ /* NOTE: "needblock" is used to handle */ /* cases where the existence of a route prohibits any */ /* routing on adjacent tracks on the same plane due to */ /* DRC restrictions (i.e., metal is too wide for single */ /* track spacing). Be sure to check the value of */ /* adjacent positions in Obs against the mask */ /* NETNUM_MASK, because NETNUM_MASK includes NO_NET. */ /* By replacing only empty and routable positions with */ /* the unique flag combination DRC_BLOCKAGE, it */ /* is possible to detect and remove the same if that */ /* net is ripped up, without touching any position */ /* originally marked NO_NET. */ /* */ /* Another NOTE: Tap offsets can cause the position */ /* in front of the offset to be unroutable. So if the */ /* segment is on a tap offset, mark the position in */ /* front as unroutable. If the segment neighbors an */ /* offset tap, then mark the tap unroutable. */ /*------------------------------------------------------*/ void writeback_segment(SEG seg, int netnum) { double dist; int i, layer; u_int sobs; NODE node; if (seg->segtype == ST_VIA) { Obs[seg->layer + 1][OGRID(seg->x1, seg->y1, seg->layer + 1)] = netnum; if (needblock[seg->layer + 1] & VIABLOCKX) { if ((seg->x1 < (NumChannelsX[seg->layer + 1] - 1)) && (Obs[seg->layer + 1][OGRID(seg->x1 + 1, seg->y1, seg->layer + 1)] & NETNUM_MASK) == 0) Obs[seg->layer + 1][OGRID(seg->x1 + 1, seg->y1, seg->layer + 1)] = DRC_BLOCKAGE; if ((seg->x1 > 0) && (Obs[seg->layer + 1][OGRID(seg->x1 - 1, seg->y1, seg->layer + 1)] & NETNUM_MASK) == 0) Obs[seg->layer + 1][OGRID(seg->x1 - 1, seg->y1, seg->layer + 1)] = DRC_BLOCKAGE; } if (needblock[seg->layer + 1] & VIABLOCKY) { if ((seg->y1 < (NumChannelsY[seg->layer + 1] - 1)) && (Obs[seg->layer + 1][OGRID(seg->x1, seg->y1 + 1, seg->layer + 1)] & NETNUM_MASK) == 0) Obs[seg->layer + 1][OGRID(seg->x1, seg->y1 + 1, seg->layer + 1)] = DRC_BLOCKAGE; if ((seg->y1 > 0) && (Obs[seg->layer + 1][OGRID(seg->x1, seg->y1 - 1, seg->layer + 1)] & NETNUM_MASK) == 0) Obs[seg->layer + 1][OGRID(seg->x1, seg->y1 - 1, seg->layer + 1)] = DRC_BLOCKAGE; } // If position itself is an offset route, then make the route position // on the forward side of the offset unroutable, on both via layers. // (Like the above code, there is no check for whether the offset // distance is enough to cause a DRC violation.) layer = (seg->layer == 0) ? 0 : seg->layer - 1; sobs = Obs[seg->layer][OGRID(seg->x1, seg->y1, seg->layer)]; if (sobs & OFFSET_TAP) { dist = Stub[layer][OGRID(seg->x1, seg->y1, seg->layer)]; if (sobs & STUBROUTE_EW) { if ((dist > 0) && (seg->x1 < (NumChannelsX[seg->layer] - 1))) { Obs[seg->layer][OGRID(seg->x1 + 1, seg->y1, seg->layer)] |= DRC_BLOCKAGE; Obs[seg->layer + 1][OGRID(seg->x1 + 1, seg->y1, seg->layer + 1)] |= DRC_BLOCKAGE; } if ((dist < 0) && (seg->x1 > 0)) { Obs[seg->layer][OGRID(seg->x1 - 1, seg->y1, seg->layer)] |= DRC_BLOCKAGE; Obs[seg->layer + 1][OGRID(seg->x1 - 1, seg->y1, seg->layer + 1)] |= DRC_BLOCKAGE; } } else if (sobs & STUBROUTE_NS) { if ((dist > 0) && (seg->y1 < (NumChannelsY[seg->layer] - 1))) { Obs[seg->layer][OGRID(seg->x1, seg->y1 + 1, seg->layer)] |= DRC_BLOCKAGE; Obs[seg->layer + 1][OGRID(seg->x1, seg->y1 + 1, seg->layer + 1)] |= DRC_BLOCKAGE; } if ((dist < 0) && (seg->y1 > 0)) { Obs[seg->layer][OGRID(seg->x1, seg->y1 - 1, seg->layer)] |= DRC_BLOCKAGE; Obs[seg->layer + 1][OGRID(seg->x1, seg->y1 - 1, seg->layer + 1)] |= DRC_BLOCKAGE; } } } } for (i = seg->x1; ; i += (seg->x2 > seg->x1) ? 1 : -1) { Obs[seg->layer][OGRID(i, seg->y1, seg->layer)] = netnum; if (needblock[seg->layer] & ROUTEBLOCKY) { if ((seg->y1 < (NumChannelsY[seg->layer] - 1)) && (Obs[seg->layer][OGRID(i, seg->y1 + 1, seg->layer)] & NETNUM_MASK) == 0) Obs[seg->layer][OGRID(i, seg->y1 + 1, seg->layer)] = DRC_BLOCKAGE; if ((seg->y1 > 0) && (Obs[seg->layer][OGRID(i, seg->y1 - 1, seg->layer)] & NETNUM_MASK) == 0) Obs[seg->layer][OGRID(i, seg->y1 - 1, seg->layer)] = DRC_BLOCKAGE; } // Check position on each side for an offset tap on a different net, and // mark the position unroutable. // // NOTE: This is a bit conservative, as it will block positions next to // an offset tap without checking if the offset distance is enough to // cause a DRC error. Could be refined. . . layer = (seg->layer == 0) ? 0 : seg->layer - 1; if (seg->y1 < (NumChannelsY[layer] - 1)) { sobs = Obs[layer][OGRID(i, seg->y1 + 1, layer)]; if ((sobs & OFFSET_TAP) && !(sobs & ROUTED_NET)) { if (sobs & STUBROUTE_NS) { dist = Stub[layer][OGRID(i, seg->y1 + 1, layer)]; if (dist < 0) { Obs[layer][OGRID(i, seg->y1 + 1, layer)] |= DRC_BLOCKAGE; } } } } if (seg->y1 > 0) { sobs = Obs[layer][OGRID(i, seg->y1 - 1, layer)]; if ((sobs & OFFSET_TAP) && !(sobs & ROUTED_NET)) { if (sobs & STUBROUTE_NS) { dist = Stub[layer][OGRID(i, seg->y1 - 1, layer)]; if (dist > 0) { Obs[layer][OGRID(i, seg->y1 - 1, layer)] |= DRC_BLOCKAGE; } } } } if (i == seg->x2) break; } for (i = seg->y1; ; i += (seg->y2 > seg->y1) ? 1 : -1) { Obs[seg->layer][OGRID(seg->x1, i, seg->layer)] = netnum; if (needblock[seg->layer] & ROUTEBLOCKX) { if ((seg->x1 < (NumChannelsX[seg->layer] - 1)) && (Obs[seg->layer][OGRID(seg->x1 + 1, i, seg->layer)] & NETNUM_MASK) == 0) Obs[seg->layer][OGRID(seg->x1 + 1, i, seg->layer)] = DRC_BLOCKAGE; if ((seg->x1 > 0) && (Obs[seg->layer][OGRID(seg->x1 - 1, i, seg->layer)] & NETNUM_MASK) == 0) Obs[seg->layer][OGRID(seg->x1 - 1, i, seg->layer)] = DRC_BLOCKAGE; } // Check position on each side for an offset tap on a different net, and // mark the position unroutable (see above). layer = (seg->layer == 0) ? 0 : seg->layer - 1; if (seg->x1 < (NumChannelsX[layer] - 1)) { sobs = Obs[layer][OGRID(seg->x1 + 1, i, layer)]; if ((sobs & OFFSET_TAP) && !(sobs & ROUTED_NET)) { if (sobs & STUBROUTE_EW) { dist = Stub[layer][OGRID(seg->x1 + 1, i, layer)]; if (dist < 0) { Obs[layer][OGRID(seg->x1 + 1, i, layer)] |= DRC_BLOCKAGE; } } } } if (seg->x1 > 0) { sobs = Obs[layer][OGRID(seg->x1 - 1, i, layer)]; if ((sobs & OFFSET_TAP) && !(sobs & ROUTED_NET)) { if (sobs & STUBROUTE_EW) { dist = Stub[layer][OGRID(seg->x1 - 1, i, layer)]; if (dist > 0) { Obs[layer][OGRID(seg->x1 - 1, i, layer)] |= DRC_BLOCKAGE; } } } } if (i == seg->y2) break; } } /*--------------------------------------------------------------*/ /* commit_proute - turn the potential route into an actual */ /* route by generating the route segments */ /* */ /* ARGS: route structure to fill; "stage" is 1 if we're on */ /* second stage routing, in which case we fill the */ /* route structure but don't modify the Obs array. */ /* */ /* RETURNS: 1 on success, 0 on stacked via failure, and */ /* -1 on failure to find a terminal. On a stacked */ /* via failure, the route is committed anyway. */ /* */ /* SIDE EFFECTS: Obs update, RT llseg added */ /*--------------------------------------------------------------*/ int commit_proute(ROUTE rt, GRIDP *ept, u_char stage) { SEG seg, lseg; int i, j, k, lay, lay2, rval; int x, y; int dx, dy, dl; u_int netnum, netobs1, netobs2, dir1, dir2; u_char first = (u_char)1; u_char dmask; u_char pflags, p2flags; PROUTE *Pr; POINT newlr, newlr2, lrtop, lrend, lrnext, lrcur, lrprev; double sreq; if (Verbose > 1) { Flush(stdout); Fprintf(stdout, "\nCommit: TotalRoutes = %d\n", TotalRoutes); } netnum = rt->netnum; Pr = &Obs2[ept->lay][OGRID(ept->x, ept->y, ept->lay)]; if (!(Pr->flags & PR_COST)) { Fprintf(stderr, "commit_proute(): impossible - terminal is not routable!\n"); return -1; } // Generate an indexed route, recording the series of predecessors and their // positions. lrtop = (POINT)malloc(sizeof(struct point_)); lrtop->x1 = ept->x; lrtop->y1 = ept->y; lrtop->layer = ept->lay; lrtop->next = NULL; lrend = lrtop; while (1) { Pr = &Obs2[lrend->layer][OGRID(lrend->x1, lrend->y1, lrend->layer)]; dmask = Pr->flags & PR_PRED_DMASK; if (dmask == PR_PRED_NONE) break; newlr = (POINT)malloc(sizeof(struct point_)); newlr->x1 = lrend->x1; newlr->y1 = lrend->y1; newlr->layer = lrend->layer; lrend->next = newlr; newlr->next = NULL; switch (dmask) { case PR_PRED_N: (newlr->y1)++; break; case PR_PRED_S: (newlr->y1)--; break; case PR_PRED_E: (newlr->x1)++; break; case PR_PRED_W: (newlr->x1)--; break; case PR_PRED_U: (newlr->layer)++; break; case PR_PRED_D: (newlr->layer)--; break; } lrend = newlr; } lrend = lrtop; // TEST: Walk through the solution, and look for stacked vias. When // found, look for an alternative path that avoids the stack. rval = 1; if (StackedContacts < (Num_layers - 1)) { POINT lrppre; POINT a, b; PROUTE *pri, *pri2; int stacks = 1, stackheight; int cx, cy, cl; int mincost, minx, miny, ci, ci2, collide, cost; while (stacks != 0) { // Keep doing until all illegal stacks are gone stacks = 0; lrcur = lrend; lrprev = lrend->next; while (lrprev != NULL) { lrppre = lrprev->next; if (lrppre == NULL) break; stackheight = 0; a = lrcur; b = lrprev; while (a->layer != b->layer) { stackheight++; a = b; b = a->next; if (b == NULL) break; } collide = FALSE; while (stackheight > StackedContacts) { // Illegal stack found stacks++; // Try to move the second contact in the path cx = lrprev->x1; cy = lrprev->y1; cl = lrprev->layer; mincost = MAXRT; dl = lrppre->layer; // Check all four positions around the contact for the // lowest cost, and make sure the position below that // is available. dx = cx + 1; // Check to the right pri = &Obs2[cl][OGRID(dx, cy, cl)]; pflags = pri->flags; cost = pri->prdata.cost; if (collide && !(pflags & (PR_COST | PR_SOURCE)) && (pri->prdata.net < MAXNETNUM)) { pflags = 0; cost = ConflictCost; } if (pflags & PR_COST) { pflags &= ~PR_COST; if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE && cost < mincost) { pri2 = &Obs2[dl][OGRID(dx, cy, dl)]; p2flags = pri2->flags; if (p2flags & PR_COST) { p2flags &= ~PR_COST; if ((p2flags & PR_PRED_DMASK) != PR_PRED_NONE && pri2->prdata.cost < MAXRT) { mincost = cost; minx = dx; miny = cy; } } else if (collide && !(p2flags & (PR_COST | PR_SOURCE)) && (pri2->prdata.net < MAXNETNUM) && ((cost + ConflictCost) < mincost)) { mincost = cost + ConflictCost; minx = dx; miny = dy; } } } dx = cx - 1; // Check to the left pri = &Obs2[cl][OGRID(dx, cy, cl)]; pflags = pri->flags; cost = pri->prdata.cost; if (collide && !(pflags & (PR_COST | PR_SOURCE)) && (pri->prdata.net < MAXNETNUM)) { pflags = 0; cost = ConflictCost; } if (pflags & PR_COST) { pflags &= ~PR_COST; if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE && cost < mincost) { pri2 = &Obs2[dl][OGRID(dx, cy, dl)]; p2flags = pri2->flags; if (p2flags & PR_COST) { p2flags &= ~PR_COST; if ((p2flags & PR_PRED_DMASK) != PR_PRED_NONE && pri2->prdata.cost < MAXRT) { mincost = cost; minx = dx; miny = cy; } } else if (collide && !(p2flags & (PR_COST | PR_SOURCE)) && (pri2->prdata.net < MAXNETNUM) && ((cost + ConflictCost) < mincost)) { mincost = cost + ConflictCost; minx = dx; miny = dy; } } } dy = cy + 1; // Check north pri = &Obs2[cl][OGRID(cx, dy, cl)]; pflags = pri->flags; cost = pri->prdata.cost; if (collide && !(pflags & (PR_COST | PR_SOURCE)) && (pri->prdata.net < MAXNETNUM)) { pflags = 0; cost = ConflictCost; } if (pflags & PR_COST) { pflags &= ~PR_COST; if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE && cost < mincost) { pri2 = &Obs2[dl][OGRID(cx, dy, dl)]; p2flags = pri2->flags; if (p2flags & PR_COST) { p2flags &= ~PR_COST; if ((p2flags & PR_PRED_DMASK) != PR_PRED_NONE && pri2->prdata.cost < MAXRT) { mincost = cost; minx = cx; miny = dy; } } else if (collide && !(p2flags & (PR_COST | PR_SOURCE)) && (pri2->prdata.net < MAXNETNUM) && ((cost + ConflictCost) < mincost)) { mincost = cost + ConflictCost; minx = dx; miny = dy; } } } dy = cy - 1; // Check south pri = &Obs2[cl][OGRID(cx, dy, cl)]; pflags = pri->flags; cost = pri->prdata.cost; if (collide && !(pflags & (PR_COST | PR_SOURCE)) && (pri->prdata.net < MAXNETNUM)) { pflags = 0; cost = ConflictCost; } if (pflags & PR_COST) { pflags &= ~PR_COST; if (pflags & PR_PRED_DMASK != PR_PRED_NONE && cost < mincost) { pri2 = &Obs2[dl][OGRID(cx, dy, dl)]; p2flags = pri2->flags; if (p2flags & PR_COST) { p2flags &= ~PR_COST; if ((p2flags & PR_PRED_DMASK) != PR_PRED_NONE && pri2->prdata.cost < MAXRT) { mincost = cost; minx = cx; miny = dy; } } else if (collide && !(p2flags & (PR_COST | PR_SOURCE)) && (pri2->prdata.net < MAXNETNUM) && ((cost + ConflictCost) < mincost)) { mincost = cost + ConflictCost; minx = dx; miny = dy; } } } // Was there an available route? If so, modify // records to route through this alternate path. If not, // then try to move the first contact instead. if (mincost < MAXRT) { pri = &Obs2[cl][OGRID(minx, miny, cl)]; newlr = (POINT)malloc(sizeof(struct point_)); newlr->x1 = minx; newlr->y1 = miny; newlr->layer = cl; pri2 = &Obs2[dl][OGRID(minx, miny, dl)]; newlr2 = (POINT)malloc(sizeof(struct point_)); newlr2->x1 = minx; newlr2->y1 = miny; newlr2->layer = dl; lrprev->next = newlr; newlr->next = newlr2; // Check if point at pri2 is equal to position of // lrppre->next. If so, bypass lrppre. if (lrnext = lrppre->next) { if (lrnext->x1 == minx && lrnext->y1 == miny && lrnext->layer == dl) { newlr->next = lrnext; free(lrppre); free(newlr2); lrppre = lrnext; // ? } else newlr2->next = lrppre; } else newlr2->next = lrppre; break; // Found a solution; we're done. } else { // If we couldn't offset lrprev position, then try // offsetting lrcur. cx = lrcur->x1; cy = lrcur->y1; cl = lrcur->layer; mincost = MAXRT; dl = lrprev->layer; dx = cx + 1; // Check to the right pri = &Obs2[cl][OGRID(dx, cy, cl)]; pflags = pri->flags; if (pflags & PR_COST) { pflags &= ~PR_COST; if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE && pri->prdata.cost < mincost) { pri2 = &Obs2[dl][OGRID(dx, cy, dl)]; p2flags = pri2->flags; if (p2flags & PR_COST) { p2flags &= ~PR_COST; if ((p2flags & PR_PRED_DMASK) != PR_PRED_NONE && pri2->prdata.cost < MAXRT) { mincost = pri->prdata.cost; minx = dx; miny = cy; } } } } dx = cx - 1; // Check to the left pri = &Obs2[cl][OGRID(dx, cy, cl)]; pflags = pri->flags; if (pflags & PR_COST) { pflags &= ~PR_COST; if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE && pri->prdata.cost < mincost) { pri2 = &Obs2[dl][OGRID(dx, cy, dl)]; p2flags = pri2->flags; if (p2flags & PR_COST) { p2flags &= ~PR_COST; if ((p2flags & PR_PRED_DMASK) != PR_PRED_NONE && pri2->prdata.cost < MAXRT) { mincost = pri->prdata.cost; minx = dx; miny = cy; } } } } dy = cy + 1; // Check north pri = &Obs2[cl][OGRID(cx, dy, cl)]; pflags = pri->flags; if (pflags & PR_COST) { pflags &= ~PR_COST; if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE && pri->prdata.cost < mincost) { pri2 = &Obs2[dl][OGRID(cx, dy, dl)]; p2flags = pri2->flags; if (p2flags & PR_COST) { p2flags &= ~PR_COST; if ((p2flags & PR_PRED_DMASK) != PR_PRED_NONE && pri2->prdata.cost < MAXRT) { mincost = pri->prdata.cost; minx = cx; miny = dy; } } } } dy = cy - 1; // Check south pri = &Obs2[cl][OGRID(cx, dy, cl)]; pflags = pri->flags; if (pflags & PR_COST) { pflags &= ~PR_COST; if ((pflags & PR_PRED_DMASK) != PR_PRED_NONE && pri->prdata.cost < mincost) { pri2 = &Obs2[dl][OGRID(cx, dy, dl)]; p2flags = pri2->flags; if (p2flags & PR_COST) { p2flags &= ~PR_COST; if ((p2flags & PR_PRED_DMASK) != PR_PRED_NONE && pri2->prdata.cost < MAXRT) { mincost = pri->prdata.cost; minx = cx; miny = dy; } } } } if (mincost < MAXRT) { newlr = (POINT)malloc(sizeof(struct point_)); newlr->x1 = minx; newlr->y1 = miny; newlr->layer = cl; newlr2 = (POINT)malloc(sizeof(struct point_)); newlr2->x1 = minx; newlr2->y1 = miny; newlr2->layer = dl; // If newlr is a source or target, then make it // the endpoint, because we have just moved the // endpoint along the source or target, and the // original endpoint position is not needed. pri = &Obs2[cl][OGRID(minx, miny, cl)]; pri2 = &Obs2[lrcur->layer][OGRID(lrcur->x1, lrcur->y1, lrcur->layer)]; if (((pri->flags & PR_SOURCE) && (pri2->flags & PR_SOURCE)) || ((pri->flags & PR_TARGET) && (pri2->flags & PR_TARGET)) && (lrcur == lrtop)) { lrtop = newlr; lrend = newlr; free(lrcur); lrcur = newlr; } else lrcur->next = newlr; newlr->next = newlr2; // Check if point at pri2 is equal to position of // lrprev->next. If so, bypass lrprev. if (lrppre->x1 == minx && lrppre->y1 == miny && lrppre->layer == dl) { newlr->next = lrppre; free(lrprev); free(newlr2); lrprev = lrcur; } else newlr2->next = lrprev; break; // Found a solution; we're done. } else if (stage == 0) { // On the first stage, we call it an error and move // on to the next net. This is a bit conservative, // but it works because failing to remove a stacked // via is a rare occurrance. if (Verbose > 0) Fprintf(stderr, "Failed to remove stacked via " "at grid point %d %d.\n", lrcur->x1, lrcur->y1); stacks = 0; rval = 0; goto cleanup; } else { if (collide == TRUE) { Fprintf(stderr, "Failed to remove stacked via " "at grid point %d %d; position may " "not be routable.\n", lrcur->x1, lrcur->y1); stacks = 0; rval = 0; goto cleanup; } // On the second stage, we will run through the // search again, but allow overwriting other // nets, which will be treated like other colliding // nets in the regular route path search. collide = TRUE; } } } lrcur = lrprev; lrprev = lrppre; } } } lrend = lrtop; lrcur = lrtop; lrprev = lrcur->next; lseg = (SEG)NULL; while (1) { seg = (SEG)malloc(sizeof(struct seg_)); seg->next = NULL; seg->segtype = (lrcur->layer == lrprev->layer) ? ST_WIRE : ST_VIA; seg->x1 = lrcur->x1; seg->y1 = lrcur->y1; seg->layer = MIN(lrcur->layer, lrprev->layer); seg->x2 = lrprev->x1; seg->y2 = lrprev->y1; dx = seg->x2 - seg->x1; dy = seg->y2 - seg->y1; // segments are in order---place final segment at end of list if (rt->segments == NULL) rt->segments = seg; else lseg->next = seg; // Continue processing predecessors as long as the direction is the same, // so we get a single long wire segment. This minimizes the number of // segments produced. Vias have to be handled one at a time, as we make // no assumptions about stacked vias. if (seg->segtype == ST_WIRE) { while ((lrnext = lrprev->next) != NULL) { lrnext = lrprev->next; if (((lrnext->x1 - lrprev->x1) == dx) && ((lrnext->y1 - lrprev->y1) == dy) && (lrnext->layer == lrprev->layer)) { lrcur = lrprev; lrprev = lrnext; seg->x2 = lrprev->x1; seg->y2 = lrprev->y1; } else break; } } if (Verbose > 3) { Fprintf(stdout, "commit: index = %d, net = %d\n", Pr->prdata.net, netnum); if (seg->segtype == ST_WIRE) { Fprintf(stdout, "commit: wire layer %d, (%d,%d) to (%d,%d)\n", seg->layer, seg->x1, seg->y1, seg->x2, seg->y2); } else { Fprintf(stdout, "commit: via %d to %d\n", seg->layer, seg->layer + 1); } Flush(stdout); } // now fill in the Obs structure with this route.... lay2 = (seg->segtype & ST_VIA) ? seg->layer + 1 : seg->layer; netobs1 = Obs[seg->layer][OGRID(seg->x1, seg->y1, seg->layer)]; netobs2 = Obs[lay2][OGRID(seg->x2, seg->y2, lay2)]; dir1 = netobs1 & PINOBSTRUCTMASK; dir2 = netobs2 & PINOBSTRUCTMASK; netobs1 &= NETNUM_MASK; netobs2 &= NETNUM_MASK; netnum |= ROUTED_NET; // Write back segment, but not on stage 2 or else the // collision information will be lost. Stage 2 uses // writeback_route to call writeback_segment after the // colliding nets have been ripped up. if (stage == (u_char)0) writeback_segment(seg, netnum); // If Obs shows this position as an obstruction, then this was a port with // no taps in reach of a grid point. This will be dealt with by moving // the via off-grid and onto the port position in emit_routes(). if (stage == (u_char)0) { if (first && dir1) { first = (u_char)0; } else if (first && dir2 && (seg->segtype & ST_VIA) && lrprev && (lrprev->layer != lay2)) { // This also applies to vias at the beginning of a route // if the path goes down instead of up (can happen on pins, // in particular) Obs[lay2][OGRID(seg->x1, seg->y1, lay2)] |= dir2; } } // Keep stub information on obstructions that have been routed // over, so that in the rip-up stage, we can return them to obstructions. Obs[seg->layer][OGRID(seg->x1, seg->y1, seg->layer)] |= dir1; Obs[lay2][OGRID(seg->x2, seg->y2, lay2)] |= dir2; // An offset route end on the previous segment, if it is a via, needs // to carry over to this one, if it is a wire route. if (lseg && ((lseg->segtype & (ST_VIA | ST_OFFSET_END)) == (ST_VIA | ST_OFFSET_END))) if (seg->segtype != ST_VIA) seg->segtype |= ST_OFFSET_START; // Check if the route ends are offset. If so, add flags. The segment // entries are integer grid points, so offsets need to be made when // the location is output. if (dir1 & OFFSET_TAP) { seg->segtype |= ST_OFFSET_START; // An offset on a via needs to be applied to the previous route // segment as well, if that route is a wire. if (lseg && (seg->segtype & ST_VIA) && !(lseg->segtype & ST_VIA)) lseg->segtype |= ST_OFFSET_END; } if (dir2 & OFFSET_TAP) seg->segtype |= ST_OFFSET_END; lrend = lrcur; // Save the last route position lrend->x1 = lrcur->x1; lrend->y1 = lrcur->y1; lrend->layer = lrcur->layer; lrcur = lrprev; // Move to the next route position lrcur->x1 = seg->x2; lrcur->y1 = seg->y2; lrprev = lrcur->next; if (lrprev == NULL) { if (dir2 && (stage == (u_char)0)) { Obs[lay2][OGRID(seg->x2, seg->y2, lay2)] |= dir2; } else if (dir1 && (seg->segtype & ST_VIA)) { // This also applies to vias at the end of a route Obs[seg->layer][OGRID(seg->x1, seg->y1, seg->layer)] |= dir1; } // Before returning, set *ept to the endpoint // position. This is for diagnostic purposes only. ept->x = lrend->x1; ept->y = lrend->y1; ept->lay = lrend->layer; // Clean up allocated memory for the route. . . while (lrtop != NULL) { lrnext = lrtop->next; free(lrtop); lrtop = lrnext; } return rval; // Success } lseg = seg; // Move to next segment position } cleanup: while (lrtop != NULL) { lrnext = lrtop->next; free(lrtop); lrtop = lrnext; } return 0; } /* commit_proute() */ /*------------------------------------------------------*/ /* writeback_route() --- */ /* */ /* This routine is the last part of the routine */ /* above. It copies the net defined by the segments */ /* in the route structure "rt" into the Obs array. */ /* This is used only for stage 2, when the writeback */ /* is not done by commit_proute because we want to */ /* rip up nets first, and also done prior to routing */ /* for any pre-defined net routes. */ /*------------------------------------------------------*/ int writeback_route(ROUTE rt) { SEG seg; int i, lay2; u_int netnum, dir1, dir2; u_char first = (u_char)1; netnum = rt->netnum | ROUTED_NET; for (seg = rt->segments; seg; seg = seg->next) { /* Save stub route information at segment ends. */ /* NOTE: Where segment end is a via, make sure we are */ /* placing the segment end on the right metal layer! */ lay2 = (seg->segtype & ST_VIA) ? seg->layer + 1 : seg->layer; dir1 = Obs[seg->layer][OGRID(seg->x1, seg->y1, seg->layer)] & PINOBSTRUCTMASK; dir2 = Obs[lay2][OGRID(seg->x2, seg->y2, lay2)] & PINOBSTRUCTMASK; writeback_segment(seg, netnum); if (first) { first = (u_char)0; if (dir1) Obs[seg->layer][OGRID(seg->x1, seg->y1, seg->layer)] |= dir1; else if (dir2) Obs[lay2][OGRID(seg->x2, seg->y2, lay2)] |= dir2; } else if (!seg->next) { if (dir1) Obs[seg->layer][OGRID(seg->x1, seg->y1, seg->layer)] |= dir1; else if (dir2) Obs[lay2][OGRID(seg->x2, seg->y2, lay2)] |= dir2; } } return TRUE; } /*------------------------------------------------------*/ /* Writeback all routes belonging to a net */ /*------------------------------------------------------*/ int writeback_all_routes(NET net) { ROUTE rt; int result = TRUE; for (rt = net->routes; rt; rt = rt->next) { if (writeback_route(rt) == FALSE) result = FALSE; } return result; } /* end of maze.c */ qrouter-1.3.33/main.c0000664000175000001440000000275712625340467013130 0ustar timusers/*--------------------------------------------------------------*/ /* qrouter entry point for non-Tcl compile version */ /*--------------------------------------------------------------*/ #include #include "qrouter.h" /*--------------------------------------------------------------*/ /* Procedure main() performs the basic route steps without any */ /* interaction or scripting, writes a DEF file as output, and */ /* exits. */ /* */ /* Precedure mimics the "standard_route" script (up to date as */ /* of November 25, 2015) */ /*--------------------------------------------------------------*/ int main(int argc, char *argv[]) { int result; result = runqrouter(argc, argv); if (result != 0) return result; read_def(NULL); maskMode = MASK_AUTO; dofirststage(0, -1); maskMode = MASK_NONE; result = dosecondstage(0, FALSE); if (result < 5) dosecondstage(0, FALSE); write_def(NULL); return 0; } /*--------------------------------------------------------------*/ /* Define graphics routines as empty subroutines. May want to */ /* provide a simple X11 graphics environment outside of Tcl/Tk */ /*--------------------------------------------------------------*/ void highlight_source() { } void highlight_dest() { } void highlight_starts(POINT glist) { } void highlight_mask() { } void highlight(int x, int y) { } void draw_net(NET net, u_char single, int *lastlayer) { } void draw_layout() { } int recalc_spacing() { return 0; } qrouter-1.3.33/lef.h0000644000175000001440000001145212406043443012734 0ustar timusers/* * lef.h -- * * This file defines things that are used by internal LEF routines in * various files. * */ #ifndef _LEFINT_H #define _LEFINT_H /* Some constants for LEF and DEF files */ #define LEF_LINE_MAX 2048 /* Maximum length fixed by LEF/DEF specifications */ #define LEF_MAX_ERRORS 100 /* Max # errors to report; limits output if */ /* something is really wrong about the file */ #define DEFAULT_WIDTH 3 /* Default metal width for routes if undefined */ #define DEFAULT_SPACING 4 /* Default spacing between metal if undefined */ /* Structure holding the counts of regular and special nets */ typedef struct { int regular; int special; u_char has_nets; } NetCount; /* Various modes for writing nets. */ #define DO_REGULAR 0 #define DO_SPECIAL 1 #define ALL_SPECIAL 2 /* treat all nets as SPECIALNETS */ /* Port classes */ enum port_classes {PORT_CLASS_DEFAULT = 0, PORT_CLASS_INPUT, PORT_CLASS_TRISTATE, PORT_CLASS_OUTPUT, PORT_CLASS_BIDIRECTIONAL, PORT_CLASS_FEEDTHROUGH}; /* Port uses */ enum port_uses {PORT_USE_DEFAULT = 0, PORT_USE_SIGNAL, PORT_USE_ANALOG, PORT_USE_POWER, PORT_USE_GROUND, PORT_USE_CLOCK}; /* Structure to hold information about spacing rules */ typedef struct _lefSpacingRule *lefSpacingPtr; typedef struct _lefSpacingRule { lefSpacingPtr next; double width; /* width, in microns */ double spacing; /* minimum spacing rule, in microns */ } lefSpacingRule; /* Structure used to maintain default routing information for each */ /* routable layer type. */ typedef struct { lefSpacingRule *spacing; /* spacing rules, ordered by width */ double width; /* nominal route width, in microns */ double pitch; /* route pitch, in microns */ double offset; /* route track offset from origin, in microns */ u_char hdirection; /* horizontal direction preferred */ } lefRoute; /* Structure used to maintain default generation information for each */ /* via or viarule (contact) type. If "cell" is non-NULL, then the via */ /* is saved in a cell (pointed to by "cell"), and "area" describes the */ /* bounding box. Otherwise, the via is formed by magic type "type" */ /* with a minimum area "area" for a single contact. */ typedef struct { struct dseg_ area; /* Area of single contact, or cell bbox */ /* in units of microns */ GATE cell; /* Cell for fixed via def, or NULL */ DSEG lr; /* Extra information for vias with */ /* more complicated geometry. */ int obsType; /* Secondary obstruction type */ } lefVia; /* Defined types for "lefClass" in the lefLayer structure */ #define CLASS_ROUTE 0 /* routing layer */ #define CLASS_VIA 1 /* via or cut layer */ #define CLASS_MASTER 2 /* masterslice layer */ #define CLASS_OVERLAP 3 /* overlap layer */ #define CLASS_IGNORE 4 /* inactive layer */ /* Structure defining a route or via layer and matching it to a magic */ /* layer type. This structure is saved in the LefInfo list. */ typedef struct _lefLayer *LefList; typedef struct _lefLayer { LefList next; /* Next layer in linked list */ char *lefName; /* CIF name of this layer */ int type; /* GDS layer type, or -1 for none */ int obsType; /* GDS type to use if this is an obstruction */ u_char lefClass; /* is this a via, route, or masterslice layer */ union { lefRoute route; /* for route layers */ lefVia via; /* for contacts */ } info; } lefLayer; /* External declaration of global variables */ extern int lefCurrentLine; extern LefList LefInfo; /* Forward declarations */ u_char LefParseEndStatement(FILE *f, char *match); void LefSkipSection(FILE *f, char *match); void LefEndStatement(FILE *f); GATE lefFindCell(char *name); char *LefNextToken(FILE *f, u_char ignore_eol); char *LefLower(char *token); DSEG LefReadGeometry(GATE lefMacro, FILE *f, float oscale); LefList LefRedefined(LefList lefl, char *redefname); void LefAddViaGeometry(FILE *f, LefList lefl, int curlayer, float oscale); DSEG LefReadRect(FILE *f, int curlayer, float oscale); int LefReadLayer(FILE *f, u_char obstruct); LefList LefFindLayer(char *token); LefList LefFindLayerByNum(int layer); int LefFindLayerNum(char *token); double LefGetRouteKeepout(int layer); double LefGetRouteWidth(int layer); double LefGetViaWidth(int base, int layer, int dir); double LefGetRouteSpacing(int layer); double LefGetRouteWideSpacing(int layer, double width); double LefGetRoutePitch(int layer); double LefGetRouteOffset(int layer); char *LefGetRouteName(int layer); int LefGetRouteOrientation(int layer); int LefGetMaxLayer(); GATE LefFindInstance(char *name); void LefHashCell(GATE gateginfo); void LefRead(char *inName); float DefRead(char *inName); void LefError(char *fmt, ...); /* Variable argument procedure requires */ /* parameter list. */ #endif /* _LEFINT_H */ qrouter-1.3.33/maze.h0000664000175000001440000000213612625161025013123 0ustar timusers/*--------------------------------------------------------------*/ /* maze.h -- details of maze router */ /*--------------------------------------------------------------*/ /* Written by Tim Edwards, June 2011, based on work of Steve */ /* Beccue. */ /*--------------------------------------------------------------*/ #ifndef MAZE_H int set_powerbus_to_net(int netnum); int set_node_to_net(NODE node, int newnet, POINT *pushlist, SEG bbox, u_char stage); int disable_node_nets(NODE node); int set_routes_to_net(NET net, int newnet, POINT *pushlist, SEG bbox, u_char stage); NODE find_unrouted_node(NET net); u_char ripup_net(NET net, u_char restore); int eval_pt(GRIDP *ept, u_char flags, u_char stage); int commit_proute(ROUTE rt, GRIDP *ept, u_char stage); void writeback_segment(SEG seg, int netnum); int writeback_route(ROUTE rt); int writeback_all_routes(NET net); NETLIST find_colliding(NET net, int *ripnum); void clear_non_source_targets(NET net, POINT *pushlist); int count_targets(NET net); #define MAZE_H #endif /* end of maze.h */ qrouter-1.3.33/config.guess0000755000175000001440000012761512406043443014346 0ustar timusers#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 # Free Software Foundation, Inc. timestamp='2009-11-20' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, 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. # Originally written by Per Bothner. Please send patches (context # diff format) to and include a ChangeLog # entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[456]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) case ${UNAME_MACHINE} in pc98) echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-gnu else echo ${UNAME_MACHINE}-unknown-linux-gnueabi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; i*86:Linux:*:*) LIBC=gnu eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in i386) eval $set_cc_for_build if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then UNAME_PROCESSOR="x86_64" fi fi ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: qrouter-1.3.33/qconfig.h0000664000175000001440000000347512616675774013651 0ustar timusers/*--------------------------------------------------------------*/ /* qconfig.h -- general purpose autorouter */ /* configuration file read/writer */ /*--------------------------------------------------------------*/ /* Written by Steve Beccue, 2003 */ /*--------------------------------------------------------------*/ /* Modified by Tim Edwards, June 2011, to separate Pitch */ /* information in X and Y dimensions. */ /*--------------------------------------------------------------*/ #ifndef QCONFIG_H extern int Num_layers; extern double PathWidth[MAX_LAYERS]; // width of the paths extern int GDSLayer[MAX_LAYERS]; // GDS layer number extern int GDSCommentLayer; // for dummy wires, etc. extern char CIFLayer[MAX_LAYERS][50]; // CIF layer name extern double PitchX[MAX_LAYERS]; // horizontal wire pitch of layer extern double PitchY[MAX_LAYERS]; // vertical wire pitch of layer extern int NumChannelsX[MAX_LAYERS]; extern int NumChannelsY[MAX_LAYERS]; extern int Vert[MAX_LAYERS]; // 1 if verticle, 0 if horizontal extern int Numpasses; // number of times to iterate in route_segs extern char StackedContacts; // Number of vias that can be stacked together extern char ViaPattern; // Type of via patterning to use extern double Xlowerbound; // Bounding Box of routes extern double Xupperbound; extern double Ylowerbound; extern double Yupperbound; extern int SegCost; extern int ViaCost; extern int JogCost; extern int XverCost; extern int BlockCost; extern int ConflictCost; extern char *ViaX[MAX_LAYERS]; extern char *ViaY[MAX_LAYERS]; int read_config(FILE *configfileptr, int is_info); void post_config(); #define QCONFIG_H #endif /* end of qconfig.h */ qrouter-1.3.33/tkcon.tcl0000775000175000001440000047575512523140044013663 0ustar timusers#!/bin/sh # \ exec ${QROUTER_WISH:=wish} "$0" ${1+"$@"} # ## tkcon.tcl ## Enhanced Tk Console, part of the VerTcl system ## ## Originally based off Brent Welch's Tcl Shell Widget ## (from "Practical Programming in Tcl and Tk") ## ## Thanks to the following (among many) for early bug reports & code ideas: ## Steven Wahl , Jan Nijtmans ## Crimmins , Wart ## ## Copyright 1995-2001 Jeffrey Hobbs ## Initiated: Thu Aug 17 15:36:47 PDT 1995 ## ## jeff.hobbs@acm.org, jeff@hobbs.org ## ## source standard_disclaimer.tcl ## source bourbon_ware.tcl ## # Proxy support for retrieving the current version of Tkcon. # # Mon Jun 25 12:19:56 2001 - Pat Thoyts # # In your tkcon.cfg or .tkconrc file put your proxy details into the # `proxy' member of the `PRIV' array. e.g.: # # set ::tkcon::PRIV(proxy) wwwproxy:8080 # # If you want to be prompted for proxy authentication details (eg for # an NT proxy server) make the second element of this variable non-nil - eg: # # set ::tkcon::PRIV(proxy) {wwwproxy:8080 1} # # Or you can set the above variable from within tkcon by calling # # tkcon master set ::tkcon:PRIV(proxy) wwwproxy:8080 # if {$tcl_version < 8.0} { return -code error "tkcon requires at least Tcl/Tk8" } else { package require Tk $tcl_version } catch {package require bogus-package-name} foreach pkg [info loaded {}] { set file [lindex $pkg 0] set name [lindex $pkg 1] if {![catch {set version [package require $name]}]} { if {[string match {} [package ifneeded $name $version]]} { package ifneeded $name $version [list load $file $name] } } } catch {unset pkg file name version} # Tk 8.4 makes previously exposed stuff private. # FIX: Update tkcon to not rely on the private Tk code. # if {![llength [info globals tkPriv]]} { ::tk::unsupported::ExposePrivateVariable tkPriv } foreach cmd {SetCursor UpDownLine Transpose ScrollPages} { if {![llength [info commands tkText$cmd]]} { ::tk::unsupported::ExposePrivateCommand tkText$cmd } } # Initialize the ::tkcon namespace # namespace eval ::tkcon { # The OPT variable is an array containing most of the optional # info to configure. COLOR has the color data. variable OPT variable COLOR # PRIV is used for internal data that only tkcon should fiddle with. variable PRIV set PRIV(WWW) [info exists embed_args] } ## ::tkcon::Init - inits tkcon # # Calls: ::tkcon::InitUI # Outputs: errors found in tkcon's resource file ## proc ::tkcon::Init {} { variable OPT variable COLOR variable PRIV global tcl_platform env argc argv tcl_interactive errorInfo if {![info exists argv]} { set argv {} set argc 0 } set tcl_interactive 1 if {[info exists PRIV(name)]} { set title $PRIV(name) } else { MainInit # some main initialization occurs later in this proc, # to go after the UI init set MainInit 1 set title Main } ## ## When setting up all the default values, we always check for ## prior existence. This allows users who embed tkcon to modify ## the initial state before tkcon initializes itself. ## # bg == {} will get bg color from the main toplevel (in InitUI) foreach {key default} { bg {} blink \#FFFF00 cursor \#000000 disabled \#4D4D4D proc \#008800 var \#FFC0D0 prompt \#8F4433 stdin \#000000 stdout \#0000FF stderr \#FF0000 } { if {![info exists COLOR($key)]} { set COLOR($key) $default } } foreach {key default} { autoload {} blinktime 500 blinkrange 1 buffer 512 calcmode 0 cols 80 debugPrompt {(level \#$level) debug [history nextid] > } dead {} expandorder {Pathname Variable Procname} font {} history 48 hoterrors 1 library {} lightbrace 1 lightcmd 1 maineval {} maxmenu 15 nontcl 0 prompt1 {ignore this, it's set below} rows 20 scrollypos right showmenu 1 showmultiple 1 showstatusbar 0 slaveeval {} slaveexit close subhistory 1 gc-delay 60000 gets {congets} usehistory 1 exec slave } { if {![info exists OPT($key)]} { set OPT($key) $default } } foreach {key default} { app {} appname {} apptype slave namesp :: cmd {} cmdbuf {} cmdsave {} event 1 deadapp 0 deadsock 0 debugging 0 displayWin . histid 0 find {} find,case 0 find,reg 0 errorInfo {} showOnStartup 1 slavealias { edit more less tkcon } slaveprocs { alias clear dir dump echo idebug lremove tkcon_puts tkcon_gets observe observe_var unalias which what } version 2.3 RCS {RCS: @(#) $Id: tkcon.tcl,v 1.1.1.1 2011/04/10 21:15:05 tim Exp $} HEADURL {http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/tkcon/tkcon/tkcon.tcl?rev=HEAD} docs "http://tkcon.sourceforge.net/" email {jeff@hobbs.org} root . } { if {![info exists PRIV($key)]} { set PRIV($key) $default } } ## NOTES FOR STAYING IN PRIMARY INTERPRETER: ## ## If you set ::tkcon::OPT(exec) to {}, then instead of a multiple ## interp model, you get tkcon operating in the main interp by default. ## This can be useful when attaching to programs that like to operate ## in the main interpter (for example, based on special wish'es). ## You can set this from the command line with -exec "" ## A side effect is that all tkcon command line args will be used ## by the first console only. #set OPT(exec) {} if {$PRIV(WWW)} { lappend PRIV(slavealias) history set OPT(prompt1) {[history nextid] % } } else { lappend PRIV(slaveprocs) tcl_unknown unknown set OPT(prompt1) {([file tail [pwd]]) [history nextid] % } } ## If we are using the default '.' toplevel, and there appear to be ## children of '.', then make sure we use a disassociated toplevel. if {$PRIV(root) == "." && [llength [winfo children .]]} { set PRIV(root) .tkcon } ## Do platform specific configuration here, other than defaults ### Use tkcon.cfg filename for resource filename on non-unix systems ### Determine what directory the resource file should be in switch $tcl_platform(platform) { macintosh { if {![interp issafe]} {cd [file dirname [info script]]} set envHome PREF_FOLDER set rcfile tkcon.cfg set histfile tkcon.hst catch {console hide} } windows { set envHome HOME set rcfile tkcon.cfg set histfile tkcon.hst } unix { set envHome HOME set rcfile .tkconrc set histfile .tkcon_history } } if {[info exists env($envHome)]} { if {![info exists PRIV(rcfile)]} { set PRIV(rcfile) [file join $env($envHome) $rcfile] } if {![info exists PRIV(histfile)]} { set PRIV(histfile) [file join $env($envHome) $histfile] } } ## Handle command line arguments before sourcing resource file to ## find if resource file is being specified (let other args pass). if {[set i [lsearch -exact $argv -rcfile]] != -1} { set PRIV(rcfile) [lindex $argv [incr i]] } if {!$PRIV(WWW) && [file exists $PRIV(rcfile)]} { set code [catch {uplevel \#0 [list source $PRIV(rcfile)]} err] } if {[info exists env(TK_CON_LIBRARY)]} { lappend ::auto_path $env(TK_CON_LIBRARY) } else { lappend ::auto_path $OPT(library) } if {![info exists ::tcl_pkgPath]} { set dir [file join [file dirname [info nameofexec]] lib] if {[llength [info commands @scope]]} { set dir [file join $dir itcl] } catch {source [file join $dir pkgIndex.tcl]} } catch {tclPkgUnknown dummy-name dummy-version} ## Handle rest of command line arguments after sourcing resource file ## and slave is created, but before initializing UI or setting packages. set slaveargs {} set slavefiles {} set truth {^(1|yes|true|on)$} for {set i 0} {$i < $argc} {incr i} { set arg [lindex $argv $i] if {[string match {-*} $arg]} { set val [lindex $argv [incr i]] ## Handle arg based options switch -glob -- $arg { -- - -argv { set argv [concat -- [lrange $argv $i end]] set argc [llength $argv] break } -color-* { set COLOR([string range $arg 7 end]) $val } -exec { set OPT(exec) $val } -main - -e - -eval { append OPT(maineval) \n$val\n } -package - -load { lappend OPT(autoload) $val } -slave { append OPT(slaveeval) \n$val\n } -nontcl { set OPT(nontcl) [regexp -nocase $truth $val]} -root { set PRIV(root) $val } -font { set OPT(font) $val } -rcfile {} default { lappend slaveargs $arg; incr i -1 } } } elseif {[file isfile $arg]} { lappend slavefiles $arg } else { lappend slaveargs $arg } } ## Create slave executable if {[string compare {} $OPT(exec)]} { uplevel \#0 ::tkcon::InitSlave $OPT(exec) $slaveargs } else { set argc [llength $slaveargs] set argv $slaveargs uplevel \#0 $slaveargs } ## Attach to the slave, EvalAttached will then be effective Attach $PRIV(appname) $PRIV(apptype) InitUI $title ## swap puts and gets with the tkcon versions to make sure all ## input and output is handled by tkcon if {![catch {rename ::puts ::tkcon_tcl_puts}]} { interp alias {} ::puts {} ::tkcon_puts } if {($OPT(gets) != "") && ![catch {rename ::gets ::tkcon_tcl_gets}]} { interp alias {} ::gets {} ::tkcon_gets } EvalSlave history keep $OPT(history) if {[info exists MainInit]} { # Source history file only for the main console, as all slave # consoles will adopt from the main's history, but still # keep separate histories if {!$PRIV(WWW) && $OPT(usehistory) && [file exists $PRIV(histfile)]} { puts -nonewline "loading history file ... " # The history file is built to be loaded in and # understood by tkcon if {[catch {uplevel \#0 [list source $PRIV(histfile)]} herr]} { puts stderr "error:\n$herr" append PRIV(errorInfo) $errorInfo\n } set PRIV(event) [EvalSlave history nextid] puts "[expr {$PRIV(event)-1}] events added" } } ## Autoload specified packages in slave set pkgs [EvalSlave package names] foreach pkg $OPT(autoload) { puts -nonewline "autoloading package \"$pkg\" ... " if {[lsearch -exact $pkgs $pkg]>-1} { if {[catch {EvalSlave package require [list $pkg]} pkgerr]} { puts stderr "error:\n$pkgerr" append PRIV(errorInfo) $errorInfo\n } else { puts "OK" } } else { puts stderr "error: package does not exist" } } ## Evaluate maineval in slave if {[string compare {} $OPT(maineval)] && \ [catch {uplevel \#0 $OPT(maineval)} merr]} { puts stderr "error in eval:\n$merr" append PRIV(errorInfo) $errorInfo\n } ## Source extra command line argument files into slave executable foreach fn $slavefiles { puts -nonewline "slave sourcing \"$fn\" ... " if {[catch {EvalSlave source [list $fn]} fnerr]} { puts stderr "error:\n$fnerr" append PRIV(errorInfo) $errorInfo\n } else { puts "OK" } } ## Evaluate slaveeval in slave if {[string compare {} $OPT(slaveeval)] && \ [catch {interp eval $OPT(exec) $OPT(slaveeval)} serr]} { puts stderr "error in slave eval:\n$serr" append PRIV(errorInfo) $errorInfo\n } ## Output any error/output that may have been returned from rcfile if {[info exists code] && $code && [string compare {} $err]} { puts stderr "error in $PRIV(rcfile):\n$err" append PRIV(errorInfo) $errorInfo } if {[string compare {} $OPT(exec)]} { StateCheckpoint [concat $PRIV(name) $OPT(exec)] slave } StateCheckpoint $PRIV(name) slave Prompt "$title console display active (Tcl$::tcl_patchLevel / Tk$::tk_patchLevel)\n" } ## ::tkcon::InitSlave - inits the slave by placing key procs and aliases in it ## It's arg[cv] are based on passed in options, while argv0 is the same as ## the master. tcl_interactive is the same as the master as well. # ARGS: slave - name of slave to init. If it does not exist, it is created. # args - args to pass to a slave as argv/argc ## proc ::tkcon::InitSlave {slave args} { variable OPT variable COLOR variable PRIV global argv0 tcl_interactive tcl_library env auto_path if {[string match {} $slave]} { return -code error "Don't init the master interpreter, goofball" } if {![interp exists $slave]} { interp create $slave } if {[interp eval $slave info command source] == ""} { $slave alias source SafeSource $slave $slave alias load SafeLoad $slave $slave alias open SafeOpen $slave $slave alias file file interp eval $slave [dump var -nocomplain tcl_library auto_path env] interp eval $slave { catch {source [file join $tcl_library init.tcl]} } interp eval $slave { catch unknown } } $slave alias exit exit interp eval $slave { # Do package require before changing around puts/gets catch {package require bogus-package-name} catch {rename ::puts ::tkcon_tcl_puts} } foreach cmd $PRIV(slaveprocs) { $slave eval [dump proc $cmd] } foreach cmd $PRIV(slavealias) { $slave alias $cmd $cmd } interp alias $slave ::ls $slave ::dir -full interp alias $slave ::puts $slave ::tkcon_puts if {$OPT(gets) != ""} { interp eval $slave { catch {rename ::gets ::tkcon_tcl_gets} } interp alias $slave ::gets $slave ::tkcon_gets } if {[info exists argv0]} {interp eval $slave [list set argv0 $argv0]} interp eval $slave set tcl_interactive $tcl_interactive \; \ set auto_path [list $auto_path] \; \ set argc [llength $args] \; \ set argv [list $args] \; { if {![llength [info command bgerror]]} { proc bgerror err { global errorInfo set body [info body bgerror] rename ::bgerror {} if {[auto_load bgerror]} { return [bgerror $err] } proc bgerror err $body tkcon bgerror $err $errorInfo } } } foreach pkg [lremove [package names] Tcl] { foreach v [package versions $pkg] { interp eval $slave [list package ifneeded $pkg $v \ [package ifneeded $pkg $v]] } } } ## ::tkcon::InitInterp - inits an interpreter by placing key ## procs and aliases in it. # ARGS: name - interp name # type - interp type (slave|interp) ## proc ::tkcon::InitInterp {name type} { variable OPT variable PRIV ## Don't allow messing up a local master interpreter if {[string match namespace $type] || ([string match slave $type] && \ [regexp {^([Mm]ain|Slave[0-9]+)$} $name])} return set old [Attach] set oldname $PRIV(namesp) catch { Attach $name $type EvalAttached { catch {rename ::puts ::tkcon_tcl_puts} } foreach cmd $PRIV(slaveprocs) { EvalAttached [dump proc $cmd] } switch -exact $type { slave { foreach cmd $PRIV(slavealias) { Main interp alias $name ::$cmd $PRIV(name) ::$cmd } } interp { set thistkcon [tk appname] foreach cmd $PRIV(slavealias) { EvalAttached "proc $cmd args { send [list $thistkcon] $cmd \$args }" } } } ## Catch in case it's a 7.4 (no 'interp alias') interp EvalAttached { catch {interp alias {} ::ls {} ::dir -full} if {[catch {interp alias {} ::puts {} ::tkcon_puts}]} { catch {rename ::tkcon_puts ::puts} } } if {$OPT(gets) != ""} { EvalAttached { catch {rename ::gets ::tkcon_tcl_gets} if {[catch {interp alias {} ::gets {} ::tkcon_gets}]} { catch {rename ::tkcon_gets ::gets} } } } return } {err} eval Attach $old AttachNamespace $oldname if {[string compare {} $err]} { return -code error $err } } ## ::tkcon::InitUI - inits UI portion (console) of tkcon ## Creates all elements of the console window and sets up the text tags # ARGS: root - widget pathname of the tkcon console root # title - title for the console root and main (.) windows # Calls: ::tkcon::InitMenus, ::tkcon::Prompt ## proc ::tkcon::InitUI {title} { variable OPT variable PRIV variable COLOR set root $PRIV(root) if {[string match . $root]} { set w {} } else { set w [toplevel $root] } if {!$PRIV(WWW)} { wm withdraw $root wm protocol $root WM_DELETE_WINDOW exit } set PRIV(base) $w ## Text Console set PRIV(console) [set con $w.text] text $con -wrap char -yscrollcommand [list $w.sy set] \ -foreground $COLOR(stdin) \ -insertbackground $COLOR(cursor) $con mark set output 1.0 $con mark set limit 1.0 if {[string compare {} $COLOR(bg)]} { $con configure -background $COLOR(bg) } set COLOR(bg) [$con cget -background] if {[string compare {} $OPT(font)]} { ## Set user-requested font, if any $con configure -font $OPT(font) } else { ## otherwise make sure the font is monospace set font [$con cget -font] if {![font metrics $font -fixed]} { font create tkconfixed -family Courier -size 12 $con configure -font tkconfixed } } set OPT(font) [$con cget -font] if {!$PRIV(WWW)} { $con configure -setgrid 1 -width $OPT(cols) -height $OPT(rows) } bindtags $con [list $con TkConsole TkConsolePost $root all] ## Menus ## catch against use in plugin if {[catch {menu $w.mbar} PRIV(menubar)]} { set PRIV(menubar) [frame $w.mbar -relief raised -bd 1] } ## Scrollbar set PRIV(scrolly) [scrollbar $w.sy -takefocus 0 -bd 1 \ -command [list $con yview]] InitMenus $PRIV(menubar) $title Bindings if {$OPT(showmenu)} { $root configure -menu $PRIV(menubar) } pack $w.sy -side $OPT(scrollypos) -fill y pack $con -fill both -expand 1 set PRIV(statusbar) [set sbar [frame $w.sbar]] label $sbar.attach -relief sunken -bd 1 -anchor w \ -textvariable ::tkcon::PRIV(StatusAttach) label $sbar.mode -relief sunken -bd 1 -anchor w \ -textvariable ::tkcon::PRIV(StatusMode) label $sbar.cursor -relief sunken -bd 1 -anchor w -width 6 \ -textvariable ::tkcon::PRIV(StatusCursor) grid $sbar.attach $sbar.mode $sbar.cursor -sticky news -padx 1 grid columnconfigure $sbar 0 -weight 1 grid columnconfigure $sbar 1 -weight 1 grid columnconfigure $sbar 2 -weight 0 if {$OPT(showstatusbar)} { pack $sbar -side bottom -fill x -before $::tkcon::PRIV(scrolly) } foreach col {prompt stdout stderr stdin proc} { $con tag configure $col -foreground $COLOR($col) } $con tag configure var -background $COLOR(var) $con tag raise sel $con tag configure blink -background $COLOR(blink) $con tag configure find -background $COLOR(blink) if {!$PRIV(WWW)} { wm title $root "tkcon $PRIV(version) $title" bind $con { scan [wm geometry [winfo toplevel %W]] "%%dx%%d" \ ::tkcon::OPT(cols) ::tkcon::OPT(rows) } if {$PRIV(showOnStartup)} { wm deiconify $root } } if {$PRIV(showOnStartup)} { focus -force $PRIV(console) } if {$OPT(gc-delay)} { after $OPT(gc-delay) ::tkcon::GarbageCollect } } ## ::tkcon::GarbageCollect - do various cleanup ops periodically to our setup ## proc ::tkcon::GarbageCollect {} { variable OPT variable PRIV set w $PRIV(console) ## Remove error tags that no longer span anything ## Make sure the tag pattern matches the unique tag prefix foreach tag [$w tag names] { if {[string match _tag* $tag] && ![llength [$w tag ranges $tag]]} { $w tag delete $tag } } if {$OPT(gc-delay)} { after $OPT(gc-delay) ::tkcon::GarbageCollect } } ## ::tkcon::Eval - evaluates commands input into console window ## This is the first stage of the evaluating commands in the console. ## They need to be broken up into consituent commands (by ::tkcon::CmdSep) in ## case a multiple commands were pasted in, then each is eval'ed (by ## ::tkcon::EvalCmd) in turn. Any uncompleted command will not be eval'ed. # ARGS: w - console text widget # Calls: ::tkcon::CmdGet, ::tkcon::CmdSep, ::tkcon::EvalCmd ## proc ::tkcon::Eval {w} { set incomplete [CmdSep [CmdGet $w] cmds last] $w mark set insert end-1c $w insert end \n if {[llength $cmds]} { foreach c $cmds {EvalCmd $w $c} $w insert insert $last {} } elseif {!$incomplete} { EvalCmd $w $last } $w see insert } ## ::tkcon::EvalCmd - evaluates a single command, adding it to history # ARGS: w - console text widget # cmd - the command to evaluate # Calls: ::tkcon::Prompt # Outputs: result of command to stdout (or stderr if error occured) # Returns: next event number ## proc ::tkcon::EvalCmd {w cmd} { variable OPT variable PRIV $w mark set output end if {[string compare {} $cmd]} { set code 0 if {$OPT(subhistory)} { set ev [EvalSlave history nextid] incr ev -1 if {[string match !! $cmd]} { set code [catch {EvalSlave history event $ev} cmd] if {!$code} {$w insert output $cmd\n stdin} } elseif {[regexp {^!(.+)$} $cmd dummy event]} { ## Check last event because history event is broken set code [catch {EvalSlave history event $ev} cmd] if {!$code && ![string match ${event}* $cmd]} { set code [catch {EvalSlave history event $event} cmd] } if {!$code} {$w insert output $cmd\n stdin} } elseif {[regexp {^\^([^^]*)\^([^^]*)\^?$} $cmd dummy old new]} { set code [catch {EvalSlave history event $ev} cmd] if {!$code} { regsub -all -- $old $cmd $new cmd $w insert output $cmd\n stdin } } elseif {$OPT(calcmode) && ![catch {expr $cmd} err]} { EvalSlave history add $cmd set cmd $err set code -1 } } if {$code} { $w insert output $cmd\n stderr } else { ## We are about to evaluate the command, so move the limit ## mark to ensure that further s don't cause double ## evaluation of this command - for cases like the command ## has a vwait or something in it $w mark set limit end if {$OPT(nontcl) && [string match interp $PRIV(apptype)]} { set code [catch {EvalSend $cmd} res] if {$code == 1} { set PRIV(errorInfo) "Non-Tcl errorInfo not available" } } elseif {[string match socket $PRIV(apptype)]} { set code [catch {EvalSocket $cmd} res] if {$code == 1} { set PRIV(errorInfo) "Socket-based errorInfo not available" } } else { set code [catch {EvalAttached $cmd} res] if {$code == 1} { if {[catch {EvalAttached [list set errorInfo]} err]} { set PRIV(errorInfo) "Error getting errorInfo:\n$err" } else { set PRIV(errorInfo) $err } } } EvalSlave history add $cmd if {$code} { if {$OPT(hoterrors)} { set tag [UniqueTag $w] $w insert output $res [list stderr $tag] \n stderr $w tag bind $tag \ [list $w tag configure $tag -under 1] $w tag bind $tag \ [list $w tag configure $tag -under 0] $w tag bind $tag \ "if {!\[info exists tkPriv(mouseMoved)\] || !\$tkPriv(mouseMoved)} \ {[list edit -attach [Attach] -type error -- $PRIV(errorInfo)]}" } else { $w insert output $res\n stderr } } elseif {[string compare {} $res]} { $w insert output $res\n stdout } } } Prompt set PRIV(event) [EvalSlave history nextid] } ## ::tkcon::EvalSlave - evaluates the args in the associated slave ## args should be passed to this procedure like they would be at ## the command line (not like to 'eval'). # ARGS: args - the command and args to evaluate ## proc ::tkcon::EvalSlave args { interp eval $::tkcon::OPT(exec) $args } ## ::tkcon::EvalOther - evaluate a command in a foreign interp or slave ## without attaching to it. No check for existence is made. # ARGS: app - interp/slave name # type - (slave|interp) ## proc ::tkcon::EvalOther { app type args } { if {[string compare slave $type]==0} { return [Slave $app $args] } else { return [uplevel 1 send [list $app] $args] } } ## ::tkcon::EvalSend - sends the args to the attached interpreter ## Varies from 'send' by determining whether attachment is dead ## when an error is received # ARGS: cmd - the command string to send across # Returns: the result of the command ## proc ::tkcon::EvalSend cmd { variable OPT variable PRIV if {$PRIV(deadapp)} { if {[lsearch -exact [winfo interps] $PRIV(app)]<0} { return } else { set PRIV(appname) [string range $PRIV(appname) 5 end] set PRIV(deadapp) 0 Prompt "\n\"$PRIV(app)\" alive\n" [CmdGet $PRIV(console)] } } set code [catch {send -displayof $PRIV(displayWin) $PRIV(app) $cmd} result] if {$code && [lsearch -exact [winfo interps] $PRIV(app)]<0} { ## Interpreter disappeared if {[string compare leave $OPT(dead)] && \ ([string match ignore $OPT(dead)] || \ [tk_dialog $PRIV(base).dead "Dead Attachment" \ "\"$PRIV(app)\" appears to have died.\ \nReturn to primary slave interpreter?" questhead 0 OK No])} { set PRIV(appname) "DEAD:$PRIV(appname)" set PRIV(deadapp) 1 } else { set err "Attached Tk interpreter \"$PRIV(app)\" died." Attach {} set PRIV(deadapp) 0 EvalSlave set errorInfo $err } Prompt \n [CmdGet $PRIV(console)] } return -code $code $result } ## ::tkcon::EvalSocket - sends the string to an interpreter attached via ## a tcp/ip socket ## ## In the EvalSocket case, ::tkcon::PRIV(app) is the socket id ## ## Must determine whether socket is dead when an error is received # ARGS: cmd - the data string to send across # Returns: the result of the command ## proc ::tkcon::EvalSocket cmd { variable OPT variable PRIV global tcl_version if {$PRIV(deadapp)} { if {![info exists PRIV(app)] || \ [catch {eof $PRIV(app)} eof] || $eof} { return } else { set PRIV(appname) [string range $PRIV(appname) 5 end] set PRIV(deadapp) 0 Prompt "\n\"$PRIV(app)\" alive\n" [CmdGet $PRIV(console)] } } # Sockets get \'s interpreted, so that users can # send things like \n\r or explicit hex values set cmd [subst -novariables -nocommands $cmd] #puts [list $PRIV(app) $cmd] set code [catch {puts $PRIV(app) $cmd ; flush $PRIV(app)} result] if {$code && [eof $PRIV(app)]} { ## Interpreter died or disappeared puts "$code eof [eof $PRIV(app)]" EvalSocketClosed } return -code $code $result } ## ::tkcon::EvalSocketEvent - fileevent command for an interpreter attached ## via a tcp/ip socket ## Must determine whether socket is dead when an error is received # ARGS: args - the args to send across # Returns: the result of the command ## proc ::tkcon::EvalSocketEvent {} { variable PRIV if {[gets $PRIV(app) line] == -1} { if {[eof $PRIV(app)]} { EvalSocketClosed } return } puts $line } ## ::tkcon::EvalSocketClosed - takes care of handling a closed eval socket ## # ARGS: args - the args to send across # Returns: the result of the command ## proc ::tkcon::EvalSocketClosed {} { variable OPT variable PRIV catch {close $PRIV(app)} if {[string compare leave $OPT(dead)] && \ ([string match ignore $OPT(dead)] || \ [tk_dialog $PRIV(base).dead "Dead Attachment" \ "\"$PRIV(app)\" appears to have died.\ \nReturn to primary slave interpreter?" questhead 0 OK No])} { set PRIV(appname) "DEAD:$PRIV(appname)" set PRIV(deadapp) 1 } else { set err "Attached Tk interpreter \"$PRIV(app)\" died." Attach {} set PRIV(deadapp) 0 EvalSlave set errorInfo $err } Prompt \n [CmdGet $PRIV(console)] } ## ::tkcon::EvalNamespace - evaluates the args in a particular namespace ## This is an override for ::tkcon::EvalAttached for when the user wants ## to attach to a particular namespace of the attached interp # ARGS: attached # namespace the namespace to evaluate in # args the args to evaluate # RETURNS: the result of the command ## proc ::tkcon::EvalNamespace { attached namespace args } { if {[llength $args]} { uplevel \#0 $attached \ [list [concat [list namespace eval $namespace] $args]] } } ## ::tkcon::Namespaces - return all the namespaces descendent from $ns ## # ## proc ::tkcon::Namespaces {{ns ::} {l {}}} { if {[string compare {} $ns]} { lappend l $ns } foreach i [EvalAttached [list namespace children $ns]] { set l [Namespaces $i $l] } return $l } ## ::tkcon::CmdGet - gets the current command from the console widget # ARGS: w - console text widget # Returns: text which compromises current command line ## proc ::tkcon::CmdGet w { if {![llength [$w tag nextrange prompt limit end]]} { $w tag add stdin limit end-1c return [$w get limit end-1c] } } ## ::tkcon::CmdSep - separates multiple commands into a list and remainder # ARGS: cmd - (possible) multiple command to separate # list - varname for the list of commands that were separated. # last - varname of any remainder (like an incomplete final command). # If there is only one command, it's placed in this var. # Returns: constituent command info in varnames specified by list & rmd. ## proc ::tkcon::CmdSep {cmd list last} { upvar 1 $list cmds $last inc set inc {} set cmds {} foreach c [split [string trimleft $cmd] \n] { if {[string compare $inc {}]} { append inc \n$c } else { append inc [string trimleft $c] } if {[info complete $inc] && ![regexp {[^\\]\\$} $inc]} { if {[regexp "^\[^#\]" $inc]} {lappend cmds $inc} set inc {} } } set i [string compare $inc {}] if {!$i && [string compare $cmds {}] && ![string match *\n $cmd]} { set inc [lindex $cmds end] set cmds [lreplace $cmds end end] } return $i } ## ::tkcon::CmdSplit - splits multiple commands into a list # ARGS: cmd - (possible) multiple command to separate # Returns: constituent commands in a list ## proc ::tkcon::CmdSplit {cmd} { set inc {} set cmds {} foreach cmd [split [string trimleft $cmd] \n] { if {[string compare {} $inc]} { append inc \n$cmd } else { append inc [string trimleft $cmd] } if {[info complete $inc] && ![regexp {[^\\]\\$} $inc]} { #set inc [string trimright $inc] if {[regexp "^\[^#\]" $inc]} {lappend cmds $inc} set inc {} } } if {[regexp "^\[^#\]" $inc]} {lappend cmds $inc} return $cmds } ## ::tkcon::UniqueTag - creates a uniquely named tag, reusing names ## Called by ::tkcon::EvalCmd # ARGS: w - text widget # Outputs: tag name guaranteed unique in the widget ## proc ::tkcon::UniqueTag {w} { set tags [$w tag names] set idx 0 while {[lsearch -exact $tags _tag[incr idx]] != -1} {} return _tag$idx } ## ::tkcon::ConstrainBuffer - This limits the amount of data in the text widget ## Called by ::tkcon::Prompt and in tkcon proc buffer/console switch cases # ARGS: w - console text widget # size - # of lines to constrain to # Outputs: may delete data in console widget ## proc ::tkcon::ConstrainBuffer {w size} { if {[$w index end] > $size} { $w delete 1.0 [expr {int([$w index end])-$size}].0 } } ## ::tkcon::Prompt - displays the prompt in the console widget # ARGS: w - console text widget # Outputs: prompt (specified in ::tkcon::OPT(prompt1)) to console ## proc ::tkcon::Prompt {{pre {}} {post {}} {prompt {}}} { variable OPT variable PRIV set w $PRIV(console) if {[string compare {} $pre]} { $w insert end $pre stdout } set i [$w index end-1c] if {!$OPT(showstatusbar)} { if {[string compare {} $PRIV(appname)]} { $w insert end ">$PRIV(appname)< " prompt } if {[string compare :: $PRIV(namesp)]} { $w insert end "<$PRIV(namesp)> " prompt } } if {[string compare {} $prompt]} { $w insert end $prompt prompt } else { $w insert end [EvalSlave subst $OPT(prompt1)] prompt } $w mark set output $i $w mark set insert end $w mark set limit insert $w mark gravity limit left if {[string compare {} $post]} { $w insert end $post stdin } ConstrainBuffer $w $OPT(buffer) set ::tkcon::PRIV(StatusCursor) [$w index insert] $w see end } ## ::tkcon::About - gives about info for tkcon ## proc ::tkcon::About {} { variable OPT variable PRIV variable COLOR set w $PRIV(base).about if {[winfo exists $w]} { wm deiconify $w } else { global tk_patchLevel tcl_patchLevel tcl_version toplevel $w wm title $w "About tkcon v$PRIV(version)" button $w.b -text Dismiss -command [list wm withdraw $w] text $w.text -height 9 -bd 1 -width 60 \ -foreground $COLOR(stdin) \ -background $COLOR(bg) \ -font $OPT(font) pack $w.b -fill x -side bottom pack $w.text -fill both -side left -expand 1 $w.text tag config center -justify center $w.text tag config title -justify center -font {Courier -18 bold} # strip down the RCS info displayed in the about box regexp {,v ([0-9\./: ]*)} $PRIV(RCS) -> RCS $w.text insert 1.0 "About tkcon v$PRIV(version)" title \ "\n\nCopyright 1995-2001 Jeffrey Hobbs, $PRIV(email)\ \nRelease Info: v$PRIV(version), CVS v$RCS\ \nDocumentation available at:\n$PRIV(docs)\ \nUsing: Tcl v$tcl_patchLevel / Tk v$tk_patchLevel" center $w.text config -state disabled } } ## ::tkcon::InitMenus - inits the menubar and popup for the console # ARGS: w - console text widget ## proc ::tkcon::InitMenus {w title} { variable OPT variable PRIV variable COLOR global tcl_platform if {[catch {menu $w.pop -tearoff 0}]} { label $w.label -text "Menus not available in plugin mode" pack $w.label return } menu $w.context -tearoff 0 -disabledforeground $COLOR(disabled) set PRIV(context) $w.context set PRIV(popup) $w.pop proc MenuButton {w m l} { $w add cascade -label $m -underline 0 -menu $w.$l return $w.$l } foreach m [list File Console Edit Interp Prefs History Help] { set l [string tolower $m] MenuButton $w $m $l $w.pop add cascade -label $m -underline 0 -menu $w.pop.$l } ## File Menu ## foreach m [list [menu $w.file -disabledforeground $COLOR(disabled)] \ [menu $w.pop.file -disabledforeground $COLOR(disabled)]] { $m add command -label "Load File" -underline 0 -command ::tkcon::Load $m add cascade -label "Save ..." -underline 0 -menu $m.save $m add separator $m add command -label "Quit" -underline 0 -accel Ctrl-q -command exit ## Save Menu ## set s $m.save menu $s -disabledforeground $COLOR(disabled) -tearoff 0 $s add command -label "All" -underline 0 \ -command {::tkcon::Save {} all} $s add command -label "History" -underline 0 \ -command {::tkcon::Save {} history} $s add command -label "Stdin" -underline 3 \ -command {::tkcon::Save {} stdin} $s add command -label "Stdout" -underline 3 \ -command {::tkcon::Save {} stdout} $s add command -label "Stderr" -underline 3 \ -command {::tkcon::Save {} stderr} } ## Console Menu ## foreach m [list [menu $w.console -disabledfore $COLOR(disabled)] \ [menu $w.pop.console -disabledfore $COLOR(disabled)]] { $m add command -label "$title Console" -state disabled $m add command -label "New Console" -underline 0 -accel Ctrl-N \ -command ::tkcon::New $m add command -label "Close Console" -underline 0 -accel Ctrl-w \ -command ::tkcon::Destroy $m add command -label "Clear Console" -underline 1 -accel Ctrl-l \ -command { clear; ::tkcon::Prompt } if {[string match unix $tcl_platform(platform)]} { $m add separator $m add command -label "Make Xauth Secure" -und 5 \ -command ::tkcon::XauthSecure } $m add separator $m add cascade -label "Attach To ..." -underline 0 -menu $m.attach ## Attach Console Menu ## set sub [menu $m.attach -disabledforeground $COLOR(disabled)] $sub add cascade -label "Interpreter" -underline 0 -menu $sub.apps $sub add cascade -label "Namespace" -underline 1 -menu $sub.name $sub add cascade -label "Socket" -underline 1 -menu $sub.sock \ -state [expr {([info tclversion] < 8.3)?"disabled":"normal"}] ## Attach Console Menu ## menu $sub.apps -disabledforeground $COLOR(disabled) \ -postcommand [list ::tkcon::AttachMenu $sub.apps] ## Attach Namespace Menu ## menu $sub.name -disabledforeground $COLOR(disabled) -tearoff 0 \ -postcommand [list ::tkcon::NamespaceMenu $sub.name] if {$::tcl_version >= 8.3} { # This uses [file channels] to create the menu, so we only # want it for newer versions of Tcl. ## Attach Socket Menu ## menu $sub.sock -disabledforeground $COLOR(disabled) -tearoff 0 \ -postcommand [list ::tkcon::SocketMenu $sub.sock] } ## Attach Display Menu ## if {![string compare "unix" $tcl_platform(platform)]} { $sub add cascade -label "Display" -und 1 -menu $sub.disp menu $sub.disp -disabledforeground $COLOR(disabled) \ -tearoff 0 \ -postcommand [list ::tkcon::DisplayMenu $sub.disp] } } ## Edit Menu ## set text $PRIV(console) foreach m [list [menu $w.edit] [menu $w.pop.edit]] { $m add command -label "Cut" -underline 2 -accel Ctrl-x \ -command [list ::tkcon::Cut $text] $m add command -label "Copy" -underline 0 -accel Ctrl-c \ -command [list ::tkcon::Copy $text] $m add command -label "Paste" -underline 0 -accel Ctrl-v \ -command [list ::tkcon::Paste $text] $m add separator $m add command -label "Find" -underline 0 -accel Ctrl-F \ -command [list ::tkcon::FindBox $text] } ## Interp Menu ## foreach m [list $w.interp $w.pop.interp] { menu $m -disabledforeground $COLOR(disabled) \ -postcommand [list ::tkcon::InterpMenu $m] } ## Prefs Menu ## foreach m [list [menu $w.prefs] [menu $w.pop.prefs]] { $m add check -label "Brace Highlighting" \ -underline 0 -variable ::tkcon::OPT(lightbrace) $m add check -label "Command Highlighting" \ -underline 0 -variable ::tkcon::OPT(lightcmd) $m add check -label "History Substitution" \ -underline 0 -variable ::tkcon::OPT(subhistory) $m add check -label "Hot Errors" \ -underline 0 -variable ::tkcon::OPT(hoterrors) $m add check -label "Non-Tcl Attachments" \ -underline 0 -variable ::tkcon::OPT(nontcl) $m add check -label "Calculator Mode" \ -underline 1 -variable ::tkcon::OPT(calcmode) $m add check -label "Show Multiple Matches" \ -underline 0 -variable ::tkcon::OPT(showmultiple) $m add check -label "Show Menubar" \ -underline 5 -variable ::tkcon::OPT(showmenu) \ -command {$::tkcon::PRIV(root) configure -menu [expr \ {$::tkcon::OPT(showmenu) ? $::tkcon::PRIV(menubar) : {}}]} $m add check -label "Show Statusbar" \ -underline 5 -variable ::tkcon::OPT(showstatusbar) \ -command { if {$::tkcon::OPT(showstatusbar)} { pack $::tkcon::PRIV(statusbar) -side bottom -fill x \ -before $::tkcon::PRIV(scrolly) } else { pack forget $::tkcon::PRIV(statusbar) } } $m add cascade -label "Scrollbar" -underline 2 -menu $m.scroll ## Scrollbar Menu ## set m [menu $m.scroll -tearoff 0] $m add radio -label "Left" -value left \ -variable ::tkcon::OPT(scrollypos) \ -command { pack config $::tkcon::PRIV(scrolly) -side left } $m add radio -label "Right" -value right \ -variable ::tkcon::OPT(scrollypos) \ -command { pack config $::tkcon::PRIV(scrolly) -side right } } ## History Menu ## foreach m [list $w.history $w.pop.history] { menu $m -disabledforeground $COLOR(disabled) \ -postcommand [list ::tkcon::HistoryMenu $m] } ## Help Menu ## foreach m [list [menu $w.help] [menu $w.pop.help]] { $m add command -label "About " -underline 0 -accel Ctrl-A \ -command ::tkcon::About $m add command -label "Retrieve Latest Version" -underline 0 \ -command ::tkcon::Retrieve } } ## ::tkcon::HistoryMenu - dynamically build the menu for attached interpreters ## # ARGS: m - menu widget ## proc ::tkcon::HistoryMenu m { variable PRIV if {![winfo exists $m]} return set id [EvalSlave history nextid] if {$PRIV(histid)==$id} return set PRIV(histid) $id $m delete 0 end while {($id>1) && ($id>$PRIV(histid)-10) && \ ![catch {EvalSlave history event [incr id -1]} tmp]} { set lbl $tmp if {[string len $lbl]>32} { set lbl [string range $tmp 0 28]... } $m add command -label "$id: $lbl" -command " $::tkcon::PRIV(console) delete limit end $::tkcon::PRIV(console) insert limit [list $tmp] $::tkcon::PRIV(console) see end ::tkcon::Eval $::tkcon::PRIV(console)" } } ## ::tkcon::InterpMenu - dynamically build the menu for attached interpreters ## # ARGS: w - menu widget ## proc ::tkcon::InterpMenu w { variable OPT variable PRIV variable COLOR if {![winfo exists $w]} return $w delete 0 end foreach {app type} [Attach] break $w add command -label "[string toupper $type]: $app" -state disabled if {($OPT(nontcl) && [string match interp $type]) || $PRIV(deadapp)} { $w add separator $w add command -state disabled -label "Communication disabled to" $w add command -state disabled -label "dead or non-Tcl interps" return } ## Show Last Error ## $w add separator $w add command -label "Show Last Error" \ -command [list tkcon error $app $type] ## Packages Cascaded Menu ## $w add separator $w add cascade -label Packages -underline 0 -menu $w.pkg set m $w.pkg if {![winfo exists $m]} { menu $m -tearoff no -disabledforeground $COLOR(disabled) \ -postcommand [list ::tkcon::PkgMenu $m $app $type] } ## State Checkpoint/Revert ## $w add separator $w add command -label "Checkpoint State" \ -command [list ::tkcon::StateCheckpoint $app $type] $w add command -label "Revert State" \ -command [list ::tkcon::StateRevert $app $type] $w add command -label "View State Change" \ -command [list ::tkcon::StateCompare $app $type] ## Init Interp ## $w add separator $w add command -label "Send tkcon Commands" \ -command [list ::tkcon::InitInterp $app $type] } ## ::tkcon::PkgMenu - fill in in the applications sub-menu ## with a list of all the applications that currently exist. ## proc ::tkcon::PkgMenu {m app type} { # just in case stuff has been added to the auto_path # we have to make sure that the errorInfo doesn't get screwed up EvalAttached { set __tkcon_error $errorInfo catch {package require bogus-package-name} set errorInfo ${__tkcon_error} unset __tkcon_error } $m delete 0 end foreach pkg [EvalAttached [list info loaded {}]] { set loaded([lindex $pkg 1]) [package provide $pkg] } foreach pkg [lremove [EvalAttached {package names}] Tcl] { set version [EvalAttached [list package provide $pkg]] if {[string compare {} $version]} { set loaded($pkg) $version } elseif {![info exists loaded($pkg)]} { set loadable($pkg) [list package require $pkg] } } foreach pkg [EvalAttached {info loaded}] { set pkg [lindex $pkg 1] if {![info exists loaded($pkg)] && ![info exists loadable($pkg)]} { set loadable($pkg) [list load {} $pkg] } } set npkg 0 foreach pkg [lsort -dictionary [array names loadable]] { foreach v [EvalAttached [list package version $pkg]] { set brkcol [expr {([incr npkg]%16)==0}] $m add command -label "Load $pkg ($v)" -command \ "::tkcon::EvalOther [list $app] $type $loadable($pkg) $v" \ -columnbreak $brkcol } } if {[info exists loaded] && [info exists loadable]} { $m add separator } foreach pkg [lsort -dictionary [array names loaded]] { $m add command -label "${pkg}$loaded($pkg) Loaded" -state disabled } } ## ::tkcon::AttachMenu - fill in in the applications sub-menu ## with a list of all the applications that currently exist. ## proc ::tkcon::AttachMenu m { variable OPT variable PRIV array set interps [set tmp [Interps]] foreach {i j} $tmp { set tknames($j) {} } $m delete 0 end set cmd {::tkcon::Prompt \n [::tkcon::CmdGet $::tkcon::PRIV(console)]} $m add radio -label {None (use local slave) } -accel Ctrl-1 \ -variable ::tkcon::PRIV(app) \ -value [concat $::tkcon::PRIV(name) $::tkcon::OPT(exec)] \ -command "::tkcon::Attach {}; $cmd" $m add separator $m add command -label "Foreign Tk Interpreters" -state disabled foreach i [lsort [lremove [winfo interps] [array names tknames]]] { $m add radio -label $i -variable ::tkcon::PRIV(app) -value $i \ -command "::tkcon::Attach [list $i] interp; $cmd" } $m add separator $m add command -label "tkcon Interpreters" -state disabled foreach i [lsort [array names interps]] { if {[string match {} $interps($i)]} { set interps($i) "no Tk" } if {[regexp {^Slave[0-9]+} $i]} { set opts [list -label "$i ($interps($i))" \ -variable ::tkcon::PRIV(app) -value $i \ -command "::tkcon::Attach [list $i] slave; $cmd"] if {[string match $PRIV(name) $i]} { append opts " -accel Ctrl-2" } eval $m add radio $opts } else { set name [concat Main $i] if {[string match Main $name]} { $m add radio -label "$name ($interps($i))" -accel Ctrl-3 \ -variable ::tkcon::PRIV(app) -value Main \ -command "::tkcon::Attach [list $name] slave; $cmd" } else { $m add radio -label "$name ($interps($i))" \ -variable ::tkcon::PRIV(app) -value $i \ -command "::tkcon::Attach [list $name] slave; $cmd" } } } } ## Displays Cascaded Menu ## proc ::tkcon::DisplayMenu m { $m delete 0 end set cmd {::tkcon::Prompt \n [::tkcon::CmdGet $::tkcon::PRIV(console)]} $m add command -label "New Display" -command ::tkcon::NewDisplay foreach disp [Display] { $m add separator $m add command -label $disp -state disabled set res [Display $disp] set win [lindex $res 0] foreach i [lsort [lindex $res 1]] { $m add radio -label $i -variable ::tkcon::PRIV(app) -value $i \ -command "::tkcon::Attach [list $i] [list dpy:$win]; $cmd" } } } ## Sockets Cascaded Menu ## proc ::tkcon::SocketMenu m { $m delete 0 end set cmd {::tkcon::Prompt \n [::tkcon::CmdGet $::tkcon::PRIV(console)]} $m add command -label "Create Connection" \ -command "::tkcon::NewSocket; $cmd" foreach sock [file channels sock*] { $m add radio -label $sock -variable ::tkcon::PRIV(app) -value $sock \ -command "::tkcon::Attach $sock socket; $cmd" } } ## Namepaces Cascaded Menu ## proc ::tkcon::NamespaceMenu m { variable PRIV variable OPT $m delete 0 end if {($PRIV(deadapp) || [string match socket $PRIV(apptype)] || \ ($OPT(nontcl) && [string match interp $PRIV(apptype)]))} { $m add command -label "No Namespaces" -state disabled return } ## Same command as for ::tkcon::AttachMenu items set cmd {::tkcon::Prompt \n [::tkcon::CmdGet $::tkcon::PRIV(console)]} set names [lsort [Namespaces ::]] if {[llength $names] > $OPT(maxmenu)} { $m add command -label "Attached to $PRIV(namesp)" -state disabled $m add command -label "List Namespaces" \ -command [list ::tkcon::NamespacesList $names] } else { foreach i $names { if {[string match :: $i]} { $m add radio -label "Main" -value $i \ -variable ::tkcon::PRIV(namesp) \ -command "::tkcon::AttachNamespace [list $i]; $cmd" } else { $m add radio -label $i -value $i \ -variable ::tkcon::PRIV(namesp) \ -command "::tkcon::AttachNamespace [list $i]; $cmd" } } } } ## Namepaces List ## proc ::tkcon::NamespacesList {names} { variable PRIV set f $PRIV(base).namespaces catch {destroy $f} toplevel $f listbox $f.names -width 30 -height 15 -selectmode single \ -yscrollcommand [list $f.scrollv set] \ -xscrollcommand [list $f.scrollh set] scrollbar $f.scrollv -command [list $f.names yview] scrollbar $f.scrollh -command [list $f.names xview] -orient horizontal frame $f.buttons button $f.cancel -text "Cancel" -command [list destroy $f] grid $f.names $f.scrollv -sticky nesw grid $f.scrollh -sticky ew grid $f.buttons -sticky nesw grid $f.cancel -in $f.buttons -pady 6 grid columnconfigure $f 0 -weight 1 grid rowconfigure $f 0 -weight 1 #fill the listbox foreach i $names { if {[string match :: $i]} { $f.names insert 0 Main } else { $f.names insert end $i } } #Bindings bind $f.names { ## Catch in case the namespace disappeared on us catch { ::tkcon::AttachNamespace [%W get [%W nearest %y]] } ::tkcon::Prompt "\n" [::tkcon::CmdGet $::tkcon::PRIV(console)] destroy [winfo toplevel %W] } } # ::tkcon::XauthSecure -- # # This removes all the names in the xhost list, and secures # the display for Tk send commands. Of course, this prevents # what might have been otherwise allowable X connections # # Arguments: # none # Results: # Returns nothing # proc ::tkcon::XauthSecure {} { global tcl_platform if {[string compare unix $tcl_platform(platform)]} { # This makes no sense outside of Unix return } set hosts [exec xhost] # the first line is info only foreach host [lrange [split $hosts \n] 1 end] { exec xhost -$host } exec xhost - tk_messageBox -title "Xhost secured" -message "Xhost secured" -icon info } ## ::tkcon::FindBox - creates minimal dialog interface to ::tkcon::Find # ARGS: w - text widget # str - optional seed string for ::tkcon::PRIV(find) ## proc ::tkcon::FindBox {w {str {}}} { variable PRIV set base $PRIV(base).find if {![winfo exists $base]} { toplevel $base wm withdraw $base wm title $base "tkcon Find" pack [frame $base.f] -fill x -expand 1 label $base.f.l -text "Find:" entry $base.f.e -textvariable ::tkcon::PRIV(find) pack [frame $base.opt] -fill x checkbutton $base.opt.c -text "Case Sensitive" \ -variable ::tkcon::PRIV(find,case) checkbutton $base.opt.r -text "Use Regexp" -variable ::tkcon::PRIV(find,reg) pack $base.f.l -side left pack $base.f.e $base.opt.c $base.opt.r -side left -fill both -expand 1 pack [frame $base.sep -bd 2 -relief sunken -height 4] -fill x pack [frame $base.btn] -fill both button $base.btn.fnd -text "Find" -width 6 button $base.btn.clr -text "Clear" -width 6 button $base.btn.dis -text "Dismiss" -width 6 eval pack [winfo children $base.btn] -padx 4 -pady 2 \ -side left -fill both focus $base.f.e bind $base.f.e [list $base.btn.fnd invoke] bind $base.f.e [list $base.btn.dis invoke] } $base.btn.fnd config -command "::tkcon::Find [list $w] \$::tkcon::PRIV(find) \ -case \$::tkcon::PRIV(find,case) -reg \$::tkcon::PRIV(find,reg)" $base.btn.clr config -command " [list $w] tag remove find 1.0 end set ::tkcon::PRIV(find) {} " $base.btn.dis config -command " [list $w] tag remove find 1.0 end wm withdraw [list $base] " if {[string compare {} $str]} { set PRIV(find) $str $base.btn.fnd invoke } if {[string compare normal [wm state $base]]} { wm deiconify $base } else { raise $base } $base.f.e select range 0 end } ## ::tkcon::Find - searches in text widget $w for $str and highlights it ## If $str is empty, it just deletes any highlighting # ARGS: w - text widget # str - string to search for # -case TCL_BOOLEAN whether to be case sensitive DEFAULT: 0 # -regexp TCL_BOOLEAN whether to use $str as pattern DEFAULT: 0 ## proc ::tkcon::Find {w str args} { $w tag remove find 1.0 end set truth {^(1|yes|true|on)$} set opts {} foreach {key val} $args { switch -glob -- $key { -c* { if {[regexp -nocase $truth $val]} { set case 1 } } -r* { if {[regexp -nocase $truth $val]} { lappend opts -regexp } } default { return -code error "Unknown option $key" } } } if {![info exists case]} { lappend opts -nocase } if {[string match {} $str]} return $w mark set findmark 1.0 while {[string compare {} [set ix [eval $w search $opts -count numc -- \ [list $str] findmark end]]]} { $w tag add find $ix ${ix}+${numc}c $w mark set findmark ${ix}+1c } $w tag configure find -background $::tkcon::COLOR(blink) catch {$w see find.first} return [expr {[llength [$w tag ranges find]]/2}] } ## ::tkcon::Attach - called to attach tkcon to an interpreter # ARGS: name - application name to which tkcon sends commands # This is either a slave interperter name or tk appname. # type - (slave|interp) type of interpreter we're attaching to # slave means it's a tkcon interpreter # interp means we'll need to 'send' to it. # Results: ::tkcon::EvalAttached is recreated to evaluate in the # appropriate interpreter ## proc ::tkcon::Attach {{name } {type slave}} { variable PRIV variable OPT if {[llength [info level 0]] == 1} { # no args were specified, return the attach info instead if {[string match {} $PRIV(appname)]} { return [list [concat $PRIV(name) $OPT(exec)] $PRIV(apptype)] } else { return [list $PRIV(appname) $PRIV(apptype)] } } set path [concat $PRIV(name) $OPT(exec)] set PRIV(displayWin) . if {[string match namespace $type]} { return [uplevel 1 ::tkcon::AttachNamespace $name] } elseif {[string match dpy:* $type]} { set PRIV(displayWin) [string range $type 4 end] } elseif {[string match sock* $type]} { global tcl_version if {[catch {eof $name} res]} { return -code error "No known channel \"$name\"" } elseif {$res} { catch {close $name} return -code error "Channel \"$name\" returned EOF" } set app $name set type socket } elseif {[string compare {} $name]} { array set interps [Interps] if {[string match {[Mm]ain} [lindex $name 0]]} { set name [lrange $name 1 end] } if {[string match $path $name]} { set name {} set app $path set type slave } elseif {[info exists interps($name)]} { if {[string match {} $name]} { set name Main; set app Main } set type slave } elseif {[interp exists $name]} { set name [concat $PRIV(name) $name] set type slave } elseif {[interp exists [concat $OPT(exec) $name]]} { set name [concat $path $name] set type slave } elseif {[lsearch -exact [winfo interps] $name] > -1} { if {[EvalSlave info exists tk_library] \ && [string match $name [EvalSlave tk appname]]} { set name {} set app $path set type slave } elseif {[set i [lsearch -exact \ [Main set ::tkcon::PRIV(interps)] $name]] != -1} { set name [lindex [Main set ::tkcon::PRIV(slaves)] $i] if {[string match {[Mm]ain} $name]} { set app Main } set type slave } else { set type interp } } else { return -code error "No known interpreter \"$name\"" } } else { set app $path } if {![info exists app]} { set app $name } array set PRIV [list app $app appname $name apptype $type deadapp 0] ## ::tkcon::EvalAttached - evaluates the args in the attached interp ## args should be passed to this procedure as if they were being ## passed to the 'eval' procedure. This procedure is dynamic to ## ensure evaluation occurs in the right interp. # ARGS: args - the command and args to evaluate ## switch -glob -- $type { slave { if {[string match {} $name]} { interp alias {} ::tkcon::EvalAttached {} \ ::tkcon::EvalSlave uplevel \#0 } elseif {[string match Main $PRIV(app)]} { interp alias {} ::tkcon::EvalAttached {} ::tkcon::Main } elseif {[string match $PRIV(name) $PRIV(app)]} { interp alias {} ::tkcon::EvalAttached {} uplevel \#0 } else { interp alias {} ::tkcon::EvalAttached {} \ ::tkcon::Slave $::tkcon::PRIV(app) } } sock* { interp alias {} ::tkcon::EvalAttached {} \ ::tkcon::EvalSlave uplevel \#0 # The file event will just puts whatever data is found # into the interpreter fconfigure $name -buffering line -blocking 0 fileevent $name readable ::tkcon::EvalSocketEvent } dpy:* - interp { if {$OPT(nontcl)} { interp alias {} ::tkcon::EvalAttached {} ::tkcon::EvalSlave set PRIV(namesp) :: } else { interp alias {} ::tkcon::EvalAttached {} ::tkcon::EvalSend } } default { return -code error "[lindex [info level 0] 0] did not specify\ a valid type: must be slave or interp" } } if {[string match slave $type] || \ (!$OPT(nontcl) && [regexp {^(interp|dpy)} $type])} { set PRIV(namesp) :: } set PRIV(StatusAttach) "$PRIV(app) ($PRIV(apptype))" return } ## ::tkcon::AttachNamespace - called to attach tkcon to a namespace # ARGS: name - namespace name in which tkcon should eval commands # Results: ::tkcon::EvalAttached will be modified ## proc ::tkcon::AttachNamespace { name } { variable PRIV variable OPT if {($OPT(nontcl) && [string match interp $PRIV(apptype)]) \ || [string match socket $PRIV(apptype)] \ || $PRIV(deadapp)} { return -code error "can't attach to namespace in attached environment" } if {[string match Main $name]} {set name ::} if {[string compare {} $name] && \ [lsearch [Namespaces ::] $name] == -1} { return -code error "No known namespace \"$name\"" } if {[regexp {^(|::)$} $name]} { ## If name=={} || ::, we want the primary namespace set alias [interp alias {} ::tkcon::EvalAttached] if {[string match ::tkcon::EvalNamespace* $alias]} { eval [list interp alias {} ::tkcon::EvalAttached {}] \ [lindex $alias 1] } set name :: } else { interp alias {} ::tkcon::EvalAttached {} ::tkcon::EvalNamespace \ [interp alias {} ::tkcon::EvalAttached] [list $name] } set PRIV(namesp) $name set PRIV(StatusAttach) "$PRIV(app) $PRIV(namesp) ($PRIV(apptype))" } ## ::tkcon::NewSocket - called to create a socket to connect to # ARGS: none # Results: It will create a socket, and attach if requested ## proc ::tkcon::NewSocket {} { variable PRIV set t $PRIV(base).newsock if {![winfo exists $t]} { toplevel $t wm withdraw $t wm title $t "tkcon Create Socket" label $t.lhost -text "Host: " entry $t.host -width 20 label $t.lport -text "Port: " entry $t.port -width 4 button $t.ok -text "OK" -command {set ::tkcon::PRIV(grab) 1} bind $t.host [list focus $t.port] bind $t.port [list focus $t.ok] bind $t.ok [list $t.ok invoke] grid $t.lhost $t.host $t.lport $t.port -sticky ew grid $t.ok - - - -sticky ew grid columnconfig $t 1 -weight 1 grid rowconfigure $t 1 -weight 1 wm transient $t $PRIV(root) wm geometry $t +[expr {([winfo screenwidth $t]-[winfo \ reqwidth $t]) / 2}]+[expr {([winfo \ screenheight $t]-[winfo reqheight $t]) / 2}] } #$t.host delete 0 end #$t.port delete 0 end wm deiconify $t raise $t grab $t focus $t.host vwait ::tkcon::PRIV(grab) grab release $t wm withdraw $t set host [$t.host get] set port [$t.port get] if {$host == ""} { return } if {[catch { set sock [socket $host $port] } err]} { tk_messageBox -title "Socket Connection Error" \ -message "Unable to connect to \"$host:$port\":\n$err" \ -icon error -type ok } else { Attach $sock socket } } ## ::tkcon::Load - sources a file into the console ## The file is actually sourced in the currently attached's interp # ARGS: fn - (optional) filename to source in # Returns: selected filename ({} if nothing was selected) ## proc ::tkcon::Load { {fn ""} } { set types { {{Tcl Files} {.tcl .tk}} {{Text Files} {.txt}} {{All Files} *} } if { [string match {} $fn] && ([catch {tk_getOpenFile -filetypes $types \ -title "Source File"} fn] || [string match {} $fn]) } { return } EvalAttached [list source $fn] } ## ::tkcon::Save - saves the console or other widget buffer to a file ## This does not eval in a slave because it's not necessary # ARGS: w - console text widget # fn - (optional) filename to save to ## proc ::tkcon::Save { {fn ""} {type ""} {opt ""} {mode w} } { variable PRIV if {![regexp -nocase {^(all|history|stdin|stdout|stderr|widget)$} $type]} { array set s { 0 All 1 History 2 Stdin 3 Stdout 4 Stderr 5 Cancel } ## Allow user to specify what kind of stuff to save set type [tk_dialog $PRIV(base).savetype "Save Type" \ "What part of the text do you want to save?" \ questhead 0 $s(0) $s(1) $s(2) $s(3) $s(4) $s(5)] if {$type == 5 || $type == -1} return set type $s($type) } if {[string match {} $fn]} { set types { {{Tcl Files} {.tcl .tk}} {{Text Files} {.txt}} {{All Files} *} } if {[catch {tk_getSaveFile -defaultextension .tcl -filetypes $types \ -title "Save $type"} fn] || [string match {} $fn]} return } set type [string tolower $type] switch $type { stdin - stdout - stderr { set data {} foreach {first last} [$PRIV(console) tag ranges $type] { lappend data [$PRIV(console) get $first $last] } set data [join $data \n] } history { set data [tkcon history] } all - default { set data [$PRIV(console) get 1.0 end-1c] } widget { set data [$opt get 1.0 end-1c] } } if {[catch {open $fn $mode} fid]} { return -code error "Save Error: Unable to open '$fn' for writing\n$fid" } puts -nonewline $fid $data close $fid } ## ::tkcon::MainInit ## This is only called for the main interpreter to include certain procs ## that we don't want to include (or rather, just alias) in slave interps. ## proc ::tkcon::MainInit {} { variable PRIV if {![info exists PRIV(slaves)]} { array set PRIV [list slave 0 slaves Main name {} \ interps [list [tk appname]]] } interp alias {} ::tkcon::Main {} ::tkcon::InterpEval Main interp alias {} ::tkcon::Slave {} ::tkcon::InterpEval proc ::tkcon::GetSlaveNum {} { set i -1 while {[interp exists Slave[incr i]]} { # oh my god, an empty loop! } return $i } ## ::tkcon::New - create new console window ## Creates a slave interpreter and sources in this script. ## All other interpreters also get a command to eval function in the ## new interpreter. ## proc ::tkcon::New {} { variable PRIV global argv0 argc argv set tmp [interp create Slave[GetSlaveNum]] lappend PRIV(slaves) $tmp load {} Tk $tmp lappend PRIV(interps) [$tmp eval [list tk appname \ "[tk appname] $tmp"]] if {[info exist argv0]} {$tmp eval [list set argv0 $argv0]} $tmp eval set argc $argc $tmp eval [list set argv $argv] $tmp eval [list namespace eval ::tkcon {}] $tmp eval [list set ::tkcon::PRIV(name) $tmp] $tmp eval [list set ::tkcon::PRIV(SCRIPT) $::tkcon::PRIV(SCRIPT)] $tmp alias exit ::tkcon::Exit $tmp $tmp alias ::tkcon::Destroy ::tkcon::Destroy $tmp $tmp alias ::tkcon::New ::tkcon::New $tmp alias ::tkcon::Main ::tkcon::InterpEval Main $tmp alias ::tkcon::Slave ::tkcon::InterpEval $tmp alias ::tkcon::Interps ::tkcon::Interps $tmp alias ::tkcon::NewDisplay ::tkcon::NewDisplay $tmp alias ::tkcon::Display ::tkcon::Display $tmp alias ::tkcon::StateCheckpoint ::tkcon::StateCheckpoint $tmp alias ::tkcon::StateCleanup ::tkcon::StateCleanup $tmp alias ::tkcon::StateCompare ::tkcon::StateCompare $tmp alias ::tkcon::StateRevert ::tkcon::StateRevert $tmp eval { if [catch {source -rsrc tkcon}] { source $::tkcon::PRIV(SCRIPT) } } return $tmp } ## ::tkcon::Exit - full exit OR destroy slave console ## This proc should only be called in the main interpreter from a slave. ## The master determines whether we do a full exit or just kill the slave. ## proc ::tkcon::Exit {slave args} { variable PRIV variable OPT ## Slave interpreter exit request if {[string match exit $OPT(slaveexit)]} { ## Only exit if it specifically is stated to do so uplevel 1 exit $args } ## Otherwise we will delete the slave interp and associated data set name [InterpEval $slave] set PRIV(interps) [lremove $PRIV(interps) [list $name]] set PRIV(slaves) [lremove $PRIV(slaves) [list $slave]] interp delete $slave StateCleanup $slave return } ## ::tkcon::Destroy - destroy console window ## This proc should only be called by the main interpreter. If it is ## called from there, it will ask before exiting tkcon. All others ## (slaves) will just have their slave interpreter deleted, closing them. ## proc ::tkcon::Destroy {{slave {}}} { variable PRIV if {[string match {} $slave]} { ## Main interpreter close request if {[tk_dialog $PRIV(base).destroyme {Quit tkcon?} \ {Closing the Main console will quit tkcon} \ warning 0 "Don't Quit" "Quit tkcon"]} exit } else { ## Slave interpreter close request set name [InterpEval $slave] set PRIV(interps) [lremove $PRIV(interps) [list $name]] set PRIV(slaves) [lremove $PRIV(slaves) [list $slave]] interp delete $slave } StateCleanup $slave return } ## We want to do a couple things before exiting... if {[catch {rename ::exit ::tkcon::FinalExit} err]} { puts stderr "tkcon might panic:\n$err" } proc ::exit args { if {$::tkcon::OPT(usehistory)} { if {[catch {open $::tkcon::PRIV(histfile) w} fid]} { puts stderr "unable to save history file:\n$fid" # pause a moment, because we are about to die finally... after 1000 } else { set max [::tkcon::EvalSlave history nextid] set id [expr {$max - $::tkcon::OPT(history)}] if {$id < 1} { set id 1 } ## FIX: This puts history in backwards!! while {($id < $max) && \ ![catch {::tkcon::EvalSlave history event $id} cmd]} { if {[string compare {} $cmd]} { puts $fid "::tkcon::EvalSlave history add [list $cmd]" } incr id } close $fid } } uplevel 1 ::tkcon::FinalExit $args } ## ::tkcon::InterpEval - passes evaluation to another named interpreter ## If the interpreter is named, but no args are given, it returns the ## [tk appname] of that interps master (not the associated eval slave). ## proc ::tkcon::InterpEval {{slave {}} args} { variable PRIV if {[string match {} $slave]} { return $PRIV(slaves) } elseif {[string match {[Mm]ain} $slave]} { set slave {} } if {[llength $args]} { return [interp eval $slave uplevel \#0 $args] } else { return [interp eval $slave tk appname] } } proc ::tkcon::Interps {{ls {}} {interp {}}} { if {[string match {} $interp]} { lappend ls {} [tk appname] } foreach i [interp slaves $interp] { if {[string compare {} $interp]} { set i "$interp $i" } if {[string compare {} [interp eval $i package provide Tk]]} { lappend ls $i [interp eval $i tk appname] } else { lappend ls $i {} } set ls [Interps $ls $i] } return $ls } proc ::tkcon::Display {{disp {}}} { variable DISP set res {} if {$disp != ""} { if {![info exists DISP($disp)]} { return } return [list $DISP($disp) [winfo interps -displayof $DISP($disp)]] } return [lsort -dictionary [array names DISP]] } proc ::tkcon::NewDisplay {} { variable PRIV variable DISP set t $PRIV(base).newdisp if {![winfo exists $t]} { toplevel $t wm withdraw $t wm title $t "tkcon Attach to Display" label $t.gets -text "New Display: " entry $t.data -width 32 button $t.ok -text "OK" -command {set ::tkcon::PRIV(grab) 1} bind $t.data [list $t.ok invoke] bind $t.ok [list $t.ok invoke] grid $t.gets $t.data -sticky ew grid $t.ok - -sticky ew grid columnconfig $t 1 -weight 1 grid rowconfigure $t 1 -weight 1 wm transient $t $PRIV(root) wm geometry $t +[expr {([winfo screenwidth $t]-[winfo \ reqwidth $t]) / 2}]+[expr {([winfo \ screenheight $t]-[winfo reqheight $t]) / 2}] } $t.data delete 0 end wm deiconify $t raise $t grab $t focus $t.data vwait ::tkcon::PRIV(grab) grab release $t wm withdraw $t set disp [$t.data get] if {$disp == ""} { return } regsub -all {\.} [string tolower $disp] ! dt set dt $PRIV(base).$dt destroy $dt if {[catch { toplevel $dt -screen $disp set interps [winfo interps -displayof $dt] if {![llength $interps]} { error "No other Tk interpreters on $disp" } send -displayof $dt [lindex $interps 0] [list info tclversion] } err]} { global env if {[info exists env(DISPLAY)]} { set myd $env(DISPLAY) } else { set myd "myDisplay:0" } tk_messageBox -title "Display Connection Error" \ -message "Unable to connect to \"$disp\":\n$err\ \nMake sure you have xauth-based permissions\ (xauth add $myd . `mcookie`), and xhost is disabled\ (xhost -) on \"$disp\"" \ -icon error -type ok destroy $dt return } set DISP($disp) $dt wm withdraw $dt bind $dt [subst {catch {unset ::tkcon::DISP($disp)}}] tk_messageBox -title "$disp Connection" \ -message "Connected to \"$disp\", found:\n[join $interps \n]" \ -type ok } ## ## The following state checkpoint/revert procedures are very sketchy ## and prone to problems. They do not track modifications to currently ## existing procedures/variables, and they can really screw things up ## if you load in libraries (especially Tk) between checkpoint and ## revert. Only with this knowledge in mind should you use these. ## ## ::tkcon::StateCheckpoint - checkpoints the current state of the system ## This allows you to return to this state with ::tkcon::StateRevert # ARGS: ## proc ::tkcon::StateCheckpoint {app type} { variable CPS variable PRIV if {[info exists CPS($type,$app,cmd)] && \ [tk_dialog $PRIV(base).warning "Overwrite Previous State?" \ "Are you sure you want to lose previously checkpointed\ state of $type \"$app\"?" questhead 1 "Do It" "Cancel"]} return set CPS($type,$app,cmd) [EvalOther $app $type info commands *] set CPS($type,$app,var) [EvalOther $app $type info vars *] return } ## ::tkcon::StateCompare - compare two states and output difference # ARGS: ## proc ::tkcon::StateCompare {app type {verbose 0}} { variable CPS variable PRIV variable OPT variable COLOR if {![info exists CPS($type,$app,cmd)]} { return -code error \ "No previously checkpointed state for $type \"$app\"" } set w $PRIV(base).compare if {[winfo exists $w]} { $w.text config -state normal $w.text delete 1.0 end } else { toplevel $w frame $w.btn scrollbar $w.sy -takefocus 0 -bd 1 -command [list $w.text yview] text $w.text -yscrollcommand [list $w.sy set] -height 12 \ -foreground $COLOR(stdin) \ -background $COLOR(bg) \ -insertbackground $COLOR(cursor) \ -font $OPT(font) pack $w.btn -side bottom -fill x pack $w.sy -side right -fill y pack $w.text -fill both -expand 1 button $w.btn.close -text "Dismiss" -width 11 \ -command [list destroy $w] button $w.btn.check -text "Recheckpoint" -width 11 button $w.btn.revert -text "Revert" -width 11 button $w.btn.expand -text "Verbose" -width 11 button $w.btn.update -text "Update" -width 11 pack $w.btn.check $w.btn.revert $w.btn.expand $w.btn.update \ $w.btn.close -side left -fill x -padx 4 -pady 2 -expand 1 $w.text tag config red -foreground red } wm title $w "Compare State: $type [list $app]" $w.btn.check config \ -command "::tkcon::StateCheckpoint [list $app] $type; \ ::tkcon::StateCompare [list $app] $type $verbose" $w.btn.revert config \ -command "::tkcon::StateRevert [list $app] $type; \ ::tkcon::StateCompare [list $app] $type $verbose" $w.btn.update config -command [info level 0] if {$verbose} { $w.btn.expand config -text Brief \ -command [list ::tkcon::StateCompare $app $type 0] } else { $w.btn.expand config -text Verbose \ -command [list ::tkcon::StateCompare $app $type 1] } ## Don't allow verbose mode unless 'dump' exists in $app ## We're assuming this is tkcon's dump command set hasdump [llength [EvalOther $app $type info commands dump]] if {$hasdump} { $w.btn.expand config -state normal } else { $w.btn.expand config -state disabled } set cmds [lremove [EvalOther $app $type info commands *] \ $CPS($type,$app,cmd)] set vars [lremove [EvalOther $app $type info vars *] \ $CPS($type,$app,var)] if {$hasdump && $verbose} { set cmds [EvalOther $app $type eval dump c -nocomplain $cmds] set vars [EvalOther $app $type eval dump v -nocomplain $vars] } $w.text insert 1.0 "NEW COMMANDS IN \"$app\":\n" red \ $cmds {} "\n\nNEW VARIABLES IN \"$app\":\n" red $vars {} raise $w $w.text config -state disabled } ## ::tkcon::StateRevert - reverts interpreter to previous state # ARGS: ## proc ::tkcon::StateRevert {app type} { variable CPS variable PRIV if {![info exists CPS($type,$app,cmd)]} { return -code error \ "No previously checkpointed state for $type \"$app\"" } if {![tk_dialog $PRIV(base).warning "Revert State?" \ "Are you sure you want to revert the state in $type \"$app\"?"\ questhead 1 "Do It" "Cancel"]} { foreach i [lremove [EvalOther $app $type info commands *] \ $CPS($type,$app,cmd)] { catch {EvalOther $app $type rename $i {}} } foreach i [lremove [EvalOther $app $type info vars *] \ $CPS($type,$app,var)] { catch {EvalOther $app $type unset $i} } } } ## ::tkcon::StateCleanup - cleans up state information in master array # ## proc ::tkcon::StateCleanup {args} { variable CPS if {![llength $args]} { foreach state [array names CPS slave,*] { if {![interp exists [string range $state 6 end]]} { unset CPS($state) } } } else { set app [lindex $args 0] set type [lindex $args 1] if {[regexp {^(|slave)$} $type]} { foreach state [array names CPS "slave,$app\[, \]*"] { if {![interp exists [string range $state 6 end]]} { unset CPS($state) } } } else { catch {unset CPS($type,$app)} } } } } ## ::tkcon::Event - get history event, search if string != {} ## look forward (next) if $int>0, otherwise look back (prev) # ARGS: W - console widget ## proc ::tkcon::Event {int {str {}}} { if {!$int} return variable PRIV set w $PRIV(console) set nextid [EvalSlave history nextid] if {[string compare {} $str]} { ## String is not empty, do an event search set event $PRIV(event) if {$int < 0 && $event == $nextid} { set PRIV(cmdbuf) $str } set len [string len $PRIV(cmdbuf)] incr len -1 if {$int > 0} { ## Search history forward while {$event < $nextid} { if {[incr event] == $nextid} { $w delete limit end $w insert limit $PRIV(cmdbuf) break } elseif { ![catch {EvalSlave history event $event} res] && [set p [string first $PRIV(cmdbuf) $res]] > -1 } { set p2 [expr {$p + [string length $PRIV(cmdbuf)]}] $w delete limit end $w insert limit $res Blink $w "limit + $p c" "limit + $p2 c" break } } set PRIV(event) $event } else { ## Search history reverse while {![catch {EvalSlave history event [incr event -1]} res]} { if {[set p [string first $PRIV(cmdbuf) $res]] > -1} { set p2 [expr {$p + [string length $PRIV(cmdbuf)]}] $w delete limit end $w insert limit $res set PRIV(event) $event Blink $w "limit + $p c" "limit + $p2 c" break } } } } else { ## String is empty, just get next/prev event if {$int > 0} { ## Goto next command in history if {$PRIV(event) < $nextid} { $w delete limit end if {[incr PRIV(event)] == $nextid} { $w insert limit $PRIV(cmdbuf) } else { $w insert limit [EvalSlave history event $PRIV(event)] } } } else { ## Goto previous command in history if {$PRIV(event) == $nextid} { set PRIV(cmdbuf) [CmdGet $w] } if {[catch {EvalSlave history event [incr PRIV(event) -1]} res]} { incr PRIV(event) } else { $w delete limit end $w insert limit $res } } } $w mark set insert end $w see end } ## ::tkcon::ErrorHighlight - magic error highlighting ## beware: voodoo included # ARGS: ## proc ::tkcon::ErrorHighlight w { variable COLOR ## do voodoo here set app [Attach] # we have to pull the text out, because text regexps are screwed on \n's. set info [$w get 1.0 end-1c] # Check for specific line error in a proc set exp(proc) "\"(\[^\"\]+)\"\n\[\t \]+\\\(procedure \"(\[^\"\]+)\"" # Check for too few args to a proc set exp(param) "parameter \"(\[^\"\]+)\" to \"(\[^\"\]+)\"" set start 1.0 while { [regexp -indices -- $exp(proc) $info junk what cmd] || [regexp -indices -- $exp(param) $info junk what cmd] } { foreach {w0 w1} $what {c0 c1} $cmd {break} set what [string range $info $w0 $w1] set cmd [string range $info $c0 $c1] if {[string match *::* $cmd]} { set res [uplevel 1 ::tkcon::EvalOther $app namespace eval \ [list [namespace qualifiers $cmd] \ [list info procs [namespace tail $cmd]]]] } else { set res [uplevel 1 ::tkcon::EvalOther $app info procs [list $cmd]] } if {[llength $res]==1} { set tag [UniqueTag $w] $w tag add $tag $start+${c0}c $start+1c+${c1}c $w tag configure $tag -foreground $COLOR(stdout) $w tag bind $tag [list $w tag configure $tag -under 1] $w tag bind $tag [list $w tag configure $tag -under 0] $w tag bind $tag "if {!\$tkPriv(mouseMoved)} \ {[list edit -attach $app -type proc -find $what -- $cmd]}" } set info [string range $info $c1 end] set start [$w index $start+${c1}c] } ## Next stage, check for procs that start a line set start 1.0 set exp(cmd) "^\"\[^\" \t\n\]+" while { [string compare {} [set ix \ [$w search -regexp -count numc -- $exp(cmd) $start end]]] } { set start [$w index $ix+${numc}c] # +1c to avoid the first quote set cmd [$w get $ix+1c $start] if {[string match *::* $cmd]} { set res [uplevel 1 ::tkcon::EvalOther $app namespace eval \ [list [namespace qualifiers $cmd] \ [list info procs [namespace tail $cmd]]]] } else { set res [uplevel 1 ::tkcon::EvalOther $app info procs [list $cmd]] } if {[llength $res]==1} { set tag [UniqueTag $w] $w tag add $tag $ix+1c $start $w tag configure $tag -foreground $COLOR(proc) $w tag bind $tag [list $w tag configure $tag -under 1] $w tag bind $tag [list $w tag configure $tag -under 0] $w tag bind $tag "if {!\$tkPriv(mouseMoved)} \ {[list edit -attach $app -type proc -- $cmd]}" } } } ## tkcon - command that allows control over the console ## This always exists in the main interpreter, and is aliased into ## other connected interpreters # ARGS: totally variable, see internal comments ## proc tkcon {cmd args} { global errorInfo switch -glob -- $cmd { buf* { ## 'buffer' Sets/Query the buffer size if {[llength $args]} { if {[regexp {^[1-9][0-9]*$} $args]} { set ::tkcon::OPT(buffer) $args # catch in case the console doesn't exist yet catch {::tkcon::ConstrainBuffer $::tkcon::PRIV(console) \ $::tkcon::OPT(buffer)} } else { return -code error "buffer must be a valid integer" } } return $::tkcon::OPT(buffer) } bg* { ## 'bgerror' Brings up an error dialog set errorInfo [lindex $args 1] bgerror [lindex $args 0] } cl* { ## 'close' Closes the console ::tkcon::Destroy } cons* { ## 'console' - passes the args to the text widget of the console. set result [uplevel 1 $::tkcon::PRIV(console) $args] ::tkcon::ConstrainBuffer $::tkcon::PRIV(console) \ $::tkcon::OPT(buffer) return $result } congets { ## 'congets' a replacement for [gets stdin] # Use the 'gets' alias of 'tkcon_gets' command instead of # calling the *get* methods directly for best compatability if {[llength $args] > 1} { return -code error "wrong # args: must be \"tkcon congets [pfix]\"" } tkcon show set old [bind TkConsole <>] bind TkConsole <> { set ::tkcon::PRIV(wait) 0 } set w $::tkcon::PRIV(console) # Make sure to move the limit to get the right data $w mark set insert end if {[llength $args]} { $w mark set limit insert $w insert end $args } else { $w mark set limit insert } $w see end vwait ::tkcon::PRIV(wait) set line [::tkcon::CmdGet $w] $w insert end \n bind TkConsole <> $old return $line } getc* { ## 'getcommand' a replacement for [gets stdin] ## This forces a complete command to be input though if {[llength $args]} { return -code error "wrong # args: must be \"tkcon getcommand\"" } tkcon show set old [bind TkConsole <>] bind TkConsole <> { set ::tkcon::PRIV(wait) 0 } set w $::tkcon::PRIV(console) # Make sure to move the limit to get the right data $w mark set insert end $w mark set limit insert $w see end vwait ::tkcon::PRIV(wait) set line [::tkcon::CmdGet $w] $w insert end \n while {![info complete $line] || [regexp {[^\\]\\$} $line]} { vwait ::tkcon::PRIV(wait) set line [::tkcon::CmdGet $w] $w insert end \n $w see end } bind TkConsole <> $old return $line } get - gets { ## 'gets' - a replacement for [gets stdin] ## This pops up a text widget to be used for stdin (local grabbed) if {[llength $args]} { return -code error "wrong # args: should be \"tkcon gets\"" } set t $::tkcon::PRIV(base).gets if {![winfo exists $t]} { toplevel $t wm withdraw $t wm title $t "tkcon gets stdin request" label $t.gets -text "\"gets stdin\" request:" text $t.data -width 32 -height 5 -wrap none \ -xscrollcommand [list $t.sx set] \ -yscrollcommand [list $t.sy set] scrollbar $t.sx -orient h -takefocus 0 -highlightthick 0 \ -command [list $t.data xview] scrollbar $t.sy -orient v -takefocus 0 -highlightthick 0 \ -command [list $t.data yview] button $t.ok -text "OK" -command {set ::tkcon::PRIV(grab) 1} bind $t.ok { %W invoke } grid $t.gets - -sticky ew grid $t.data $t.sy -sticky news grid $t.sx -sticky ew grid $t.ok - -sticky ew grid columnconfig $t 0 -weight 1 grid rowconfig $t 1 -weight 1 wm transient $t $::tkcon::PRIV(root) wm geometry $t +[expr {([winfo screenwidth $t]-[winfo \ reqwidth $t]) / 2}]+[expr {([winfo \ screenheight $t]-[winfo reqheight $t]) / 2}] } $t.data delete 1.0 end wm deiconify $t raise $t grab $t focus $t.data vwait ::tkcon::PRIV(grab) grab release $t wm withdraw $t return [$t.data get 1.0 end-1c] } err* { ## Outputs stack caused by last error. ## error handling with pizazz (but with pizza would be nice too) if {[llength $args]==2} { set app [lindex $args 0] set type [lindex $args 1] if {[catch {::tkcon::EvalOther $app $type set errorInfo} info]} { set info "error getting info from $type $app:\n$info" } } else { set info $::tkcon::PRIV(errorInfo) } if {[string match {} $info]} { set info "errorInfo empty" } ## If args is empty, the -attach switch just ignores it edit -attach $args -type error -- $info } fi* { ## 'find' string ::tkcon::Find $::tkcon::PRIV(console) $args } fo* { ## 'font' ?fontname? - gets/sets the font of the console if {[llength $args]} { if {[info exists ::tkcon::PRIV(console)] && \ [winfo exists $::tkcon::PRIV(console)]} { $::tkcon::PRIV(console) config -font $args set ::tkcon::OPT(font) [$::tkcon::PRIV(console) cget -font] } else { set ::tkcon::OPT(font) $args } } return $::tkcon::OPT(font) } hid* - with* { ## 'hide' 'withdraw' - hides the console. wm withdraw $::tkcon::PRIV(root) } his* { ## 'history' set sub {\2} if {[string match -new* $args]} { append sub "\n"} set h [::tkcon::EvalSlave history] regsub -all "( *\[0-9\]+ |\t)(\[^\n\]*\n?)" $h $sub h return $h } ico* { ## 'iconify' - iconifies the console with 'iconify'. wm iconify $::tkcon::PRIV(root) } mas* - eval { ## 'master' - evals contents in master interpreter uplevel \#0 $args } set { ## 'set' - set (or get, or unset) simple vars (not whole arrays) ## from the master console interpreter ## possible formats: ## tkcon set ## tkcon set ## tkcon set w ## tkcon set u ## tkcon set r if {[llength $args]==5} { ## This is for use w/ 'tkcon upvar' and only works with slaves foreach {var i var1 var2 op} $args break if {[string compare {} $var2]} { append var1 "($var2)" } switch $op { u { uplevel \#0 [list unset $var] } w { return [uplevel \#0 [list set $var \ [interp eval $i [list set $var1]]]] } r { return [interp eval $i [list set $var1 \ [uplevel \#0 [list set $var]]]] } } } elseif {[llength $args] == 1} { upvar \#0 [lindex $args 0] var if {[array exists var]} { return [array get var] } else { return $var } } return [uplevel \#0 set $args] } append { ## Modify a var in the master environment using append return [uplevel \#0 append $args] } lappend { ## Modify a var in the master environment using lappend return [uplevel \#0 lappend $args] } sh* - dei* { ## 'show|deiconify' - deiconifies the console. wm deiconify $::tkcon::PRIV(root) raise $::tkcon::PRIV(root) focus -force $::tkcon::PRIV(console) } ti* { ## 'title' ?title? - gets/sets the console's title if {[llength $args]} { return [wm title $::tkcon::PRIV(root) [join $args]] } else { return [wm title $::tkcon::PRIV(root)] } } upv* { ## 'upvar' masterVar slaveVar ## link slave variable slaveVar to the master variable masterVar ## only works masters<->slave set masterVar [lindex $args 0] set slaveVar [lindex $args 1] if {[info exists $masterVar]} { interp eval $::tkcon::OPT(exec) \ [list set $slaveVar [set $masterVar]] } else { catch {interp eval $::tkcon::OPT(exec) [list unset $slaveVar]} } interp eval $::tkcon::OPT(exec) \ [list trace variable $slaveVar rwu \ [list tkcon set $masterVar $::tkcon::OPT(exec)]] return } v* { return $::tkcon::PRIV(version) } default { ## tries to determine if the command exists, otherwise throws error set new ::tkcon::[string toupper \ [string index $cmd 0]][string range $cmd 1 end] if {[llength [info command $new]]} { uplevel \#0 $new $args } else { return -code error "bad option \"$cmd\": must be\ [join [lsort [list attach close console destroy \ font hide iconify load main master new save show \ slave deiconify version title bgerror]] {, }]" } } } } ## ## Some procedures to make up for lack of built-in shell commands ## ## tkcon_puts - ## This allows me to capture all stdout/stderr to the console window ## This will be renamed to 'puts' at the appropriate time during init ## # ARGS: same as usual # Outputs: the string with a color-coded text tag ## proc tkcon_puts args { set len [llength $args] foreach {arg1 arg2 arg3} $args { break } if {$len == 1} { set sarg $arg1 set nl 1 set farg stdout } elseif {$len == 2} { if {![string compare $arg1 -nonewline]} { set sarg $arg2 set farg stdout set nl 0 } elseif {![string compare $arg1 stdout] \ || ![string compare $arg1 stderr]} { set sarg $arg2 set farg $arg1 set nl 1 } else { set len 0 } } elseif {$len == 3} { if {![string compare $arg1 -nonewline] \ && (![string compare $arg2 stdout] \ || ![string compare $arg2 stderr])} { set sarg $arg3 set farg $arg2 set nl 0 } elseif {(![string compare $arg1 stdout] \ || ![string compare $arg1 stderr]) \ && ![string compare $arg3 nonewline]} { set sarg $arg2 set farg $arg1 set nl 0 } else { set len 0 } } else { set len 0 } ## $len == 0 means it wasn't handled by tkcon above. ## if {$len != 0} { ## "poor man's" \r substitution---erase everything on the output ## line and print from character after the \r set rpt [string last \r $sarg] if {$rpt >= 0} { tkcon console delete "insert linestart" "insert lineend" set sarg [string range $sarg [expr {$rpt + 1}] end] } set bpt [string first \b $sarg] if {$bpt >= 0} { set narg [string range $sarg [expr {$bpt + 1}] end] set sarg [string range $sarg 0 [expr {$bpt - 1}]] set nl 0 } if {$nl == 0} { tkcon console insert output $sarg $farg } else { tkcon console insert output "$sarg\n" $farg } if {$bpt >= 0} { tkcon console delete "insert -1 char" insert if {$nl == 0} { tkcon_puts $farg $narg nonewline } else { tkcon_puts $farg $narg } } } else { global errorCode errorInfo if {[catch "tkcon_tcl_puts $args" msg]} { regsub tkcon_tcl_puts $msg puts msg regsub -all tkcon_tcl_puts $errorInfo puts errorInfo return -code error $msg } return $msg } ## WARNING: This update should behave well because it uses idletasks, ## however, if there are weird looping problems with events, or ## hanging in waits, try commenting this out. if {$len} { tkcon console see output update idletasks } } ## tkcon_gets - ## This allows me to capture all stdin input without needing to stdin ## This will be renamed to 'gets' at the appropriate time during init ## # ARGS: same as gets # Outputs: same as gets ## proc tkcon_gets args { set len [llength $args] if {$len != 1 && $len != 2} { return -code error \ "wrong # args: should be \"gets channelId ?varName?\"" } if {[string compare stdin [lindex $args 0]]} { return [uplevel 1 tkcon_tcl_gets $args] } set gtype [tkcon set ::tkcon::OPT(gets)] if {$gtype == ""} { set gtype congets } set data [tkcon $gtype] if {$len == 2} { upvar 1 [lindex $args 1] var set var $data return [string length $data] } return $data } ## edit - opens a file/proc/var for reading/editing ## # Arguments: # type proc/file/var # what the actual name of the item # Returns: nothing ## proc edit {args} { array set opts {-find {} -type {} -attach {}} while {[string match -* [lindex $args 0]]} { switch -glob -- [lindex $args 0] { -f* { set opts(-find) [lindex $args 1] } -a* { set opts(-attach) [lindex $args 1] } -t* { set opts(-type) [lindex $args 1] } -- { set args [lreplace $args 0 0]; break } default {return -code error "unknown option \"[lindex $args 0]\""} } set args [lreplace $args 0 1] } # determine who we are dealing with if {[llength $opts(-attach)]} { foreach {app type} $opts(-attach) {break} } else { foreach {app type} [tkcon attach] {break} } set word [lindex $args 0] if {[string match {} $opts(-type)]} { if {[llength [::tkcon::EvalOther $app $type info commands [list $word]]]} { set opts(-type) "proc" } elseif {[llength [::tkcon::EvalOther $app $type info vars [list $word]]]} { set opts(-type) "var" } elseif {[::tkcon::EvalOther $app $type file isfile [list $word]]} { set opts(-type) "file" } } if {[string compare $opts(-type) {}]} { # Create unique edit window toplevel set w $::tkcon::PRIV(base).__edit set i 0 while {[winfo exists $w[incr i]]} {} append w $i toplevel $w wm withdraw $w if {[string length $word] > 12} { wm title $w "tkcon Edit: [string range $word 0 9]..." } else { wm title $w "tkcon Edit: $word" } text $w.text -wrap none \ -xscrollcommand [list $w.sx set] \ -yscrollcommand [list $w.sy set] \ -foreground $::tkcon::COLOR(stdin) \ -background $::tkcon::COLOR(bg) \ -insertbackground $::tkcon::COLOR(cursor) \ -font $::tkcon::OPT(font) scrollbar $w.sx -orient h -takefocus 0 -bd 1 \ -command [list $w.text xview] scrollbar $w.sy -orient v -takefocus 0 -bd 1 \ -command [list $w.text yview] set menu [menu $w.mbar] $w configure -menu $menu ## File Menu ## set m [menu [::tkcon::MenuButton $menu File file]] $m add command -label "Save As..." -underline 0 \ -command [list ::tkcon::Save {} widget $w.text] $m add command -label "Append To..." -underline 0 \ -command [list ::tkcon::Save {} widget $w.text a+] $m add separator $m add command -label "Dismiss" -underline 0 -accel "Ctrl-w" \ -command [list destroy $w] bind $w [list destroy $w] bind $w <$::tkcon::PRIV(meta)-w> [list destroy $w] ## Edit Menu ## set text $w.text set m [menu [::tkcon::MenuButton $menu Edit edit]] $m add command -label "Cut" -under 2 \ -command [list tk_textCut $text] $m add command -label "Copy" -under 0 \ -command [list tk_textCopy $text] $m add command -label "Paste" -under 0 \ -command [list tk_textPaste $text] $m add separator $m add command -label "Find" -under 0 \ -command [list ::tkcon::FindBox $text] ## Send To Menu ## set m [menu [::tkcon::MenuButton $menu "Send To..." send]] $m add command -label "Send To $app" -underline 0 \ -command "::tkcon::EvalOther [list $app] $type \ eval \[$w.text get 1.0 end-1c\]" set other [tkcon attach] if {[string compare $other [list $app $type]]} { $m add command -label "Send To [lindex $other 0]" \ -command "::tkcon::EvalOther $other \ eval \[$w.text get 1.0 end-1c\]" } grid $w.text - $w.sy -sticky news grid $w.sx - -sticky ew grid columnconfigure $w 0 -weight 1 grid columnconfigure $w 1 -weight 1 grid rowconfigure $w 0 -weight 1 } else { return -code error "unrecognized type '$word'" } switch -glob -- $opts(-type) { proc* { $w.text insert 1.0 \ [::tkcon::EvalOther $app $type dump proc [list $word]] } var* { $w.text insert 1.0 \ [::tkcon::EvalOther $app $type dump var [list $word]] } file { $w.text insert 1.0 [::tkcon::EvalOther $app $type eval \ [subst -nocommands { set __tkcon(fid) [open $word r] set __tkcon(data) [read \$__tkcon(fid)] close \$__tkcon(fid) after 1000 unset __tkcon return \$__tkcon(data) } ]] } error* { $w.text insert 1.0 [join $args \n] ::tkcon::ErrorHighlight $w.text } default { $w.text insert 1.0 [join $args \n] } } wm deiconify $w focus $w.text if {[string compare $opts(-find) {}]} { ::tkcon::Find $w.text $opts(-find) -case 1 } } interp alias {} ::more {} ::edit interp alias {} ::less {} ::edit ## echo ## Relaxes the one string restriction of 'puts' # ARGS: any number of strings to output to stdout ## proc echo args { puts [concat $args] } ## clear - clears the buffer of the console (not the history though) ## This is executed in the parent interpreter ## proc clear {{pcnt 100}} { if {![regexp {^[0-9]*$} $pcnt] || $pcnt < 1 || $pcnt > 100} { return -code error \ "invalid percentage to clear: must be 1-100 (100 default)" } elseif {$pcnt == 100} { tkcon console delete 1.0 end } else { set tmp [expr {$pcnt/100.0*[tkcon console index end]}] tkcon console delete 1.0 "$tmp linestart" } } ## alias - akin to the csh alias command ## If called with no args, then it dumps out all current aliases ## If called with one arg, returns the alias of that arg (or {} if none) # ARGS: newcmd - (optional) command to bind alias to # args - command and args being aliased ## proc alias {{newcmd {}} args} { if {[string match {} $newcmd]} { set res {} foreach a [interp aliases] { lappend res [list $a -> [interp alias {} $a]] } return [join $res \n] } elseif {![llength $args]} { interp alias {} $newcmd } else { eval interp alias [list {} $newcmd {}] $args } } ## unalias - unaliases an alias'ed command # ARGS: cmd - command to unbind as an alias ## proc unalias {cmd} { interp alias {} $cmd {} } ## dump - outputs variables/procedure/widget info in source'able form. ## Accepts glob style pattern matching for the names # # ARGS: type - type of thing to dump: must be variable, procedure, widget # # OPTS: -nocomplain # don't complain if no items of the specified type are found # -filter pattern # specifies a glob filter pattern to be used by the variable # method as an array filter pattern (it filters down for # nested elements) and in the widget method as a config # option filter pattern # -- forcibly ends options recognition # # Returns: the values of the requested items in a 'source'able form ## proc dump {type args} { set whine 1 set code ok if {![llength $args]} { ## If no args, assume they gave us something to dump and ## we'll try anything set args $type set type any } while {[string match -* [lindex $args 0]]} { switch -glob -- [lindex $args 0] { -n* { set whine 0; set args [lreplace $args 0 0] } -f* { set fltr [lindex $args 1]; set args [lreplace $args 0 1] } -- { set args [lreplace $args 0 0]; break } default {return -code error "unknown option \"[lindex $args 0]\""} } } if {$whine && ![llength $args]} { return -code error "wrong \# args: [lindex [info level 0] 0] type\ ?-nocomplain? ?-filter pattern? ?--? pattern ?pattern ...?" } set res {} switch -glob -- $type { c* { # command # outputs commands by figuring out, as well as possible, what it is # this does not attempt to auto-load anything foreach arg $args { if {[llength [set cmds [info commands $arg]]]} { foreach cmd [lsort $cmds] { if {[lsearch -exact [interp aliases] $cmd] > -1} { append res "\#\# ALIAS: $cmd =>\ [interp alias {} $cmd]\n" } elseif { [llength [info procs $cmd]] || ([string match *::* $cmd] && [llength [namespace eval [namespace qual $cmd] \ info procs [namespace tail $cmd]]]) } { if {[catch {dump p -- $cmd} msg] && $whine} { set code error } append res $msg\n } else { append res "\#\# COMMAND: $cmd\n" } } } elseif {$whine} { append res "\#\# No known command $arg\n" set code error } } } v* { # variable # outputs variables value(s), whether array or simple. if {![info exists fltr]} { set fltr * } foreach arg $args { if {![llength [set vars [uplevel 1 info vars [list $arg]]]]} { if {[uplevel 1 info exists $arg]} { set vars $arg } elseif {$whine} { append res "\#\# No known variable $arg\n" set code error continue } else { continue } } foreach var [lsort $vars] { if {[uplevel 1 [list info locals $var]] == ""} { # use the proper scope of the var, but # namespace which won't id locals correctly set var [uplevel 1 \ [list namespace which -variable $var]] } upvar 1 $var v if {[array exists v] || [catch {string length $v}]} { set nst {} append res "array set [list $var] \{\n" if {[array size v]} { foreach i [lsort [array names v $fltr]] { upvar 0 v\($i\) __a if {[array exists __a]} { append nst "\#\# NESTED ARRAY ELEM: $i\n" append nst "upvar 0 [list $var\($i\)] __a;\ [dump v -filter $fltr __a]\n" } else { append res " [list $i]\t[list $v($i)]\n" } } } else { ## empty array append res " empty array\n" append nst "unset [list $var](empty)\n" } append res "\}\n$nst" } else { append res [list set $var $v]\n } } } } p* { # procedure foreach arg $args { if { ![llength [set procs [info proc $arg]]] && ([string match *::* $arg] && [llength [set ps [namespace eval \ [namespace qualifier $arg] \ info procs [namespace tail $arg]]]]) } { set procs {} set namesp [namespace qualifier $arg] foreach p $ps { lappend procs ${namesp}::$p } } if {[llength $procs]} { foreach p [lsort $procs] { set as {} foreach a [info args $p] { if {[info default $p $a tmp]} { lappend as [list $a $tmp] } else { lappend as $a } } append res [list proc $p $as [info body $p]]\n } } elseif {$whine} { append res "\#\# No known proc $arg\n" set code error } } } w* { # widget ## The user should have Tk loaded if {![llength [info command winfo]]} { return -code error "winfo not present, cannot dump widgets" } if {![info exists fltr]} { set fltr .* } foreach arg $args { if {[llength [set ws [info command $arg]]]} { foreach w [lsort $ws] { if {[winfo exists $w]} { if {[catch {$w configure} cfg]} { append res "\#\# Widget $w\ does not support configure method" set code error } else { append res "\#\# [winfo class $w]\ $w\n$w configure" foreach c $cfg { if {[llength $c] != 5} continue ## Check to see that the option does ## not match the default, then check ## the item against the user filter if {[string compare [lindex $c 3] \ [lindex $c 4]] && \ [regexp -nocase -- $fltr $c]} { append res " \\\n\t[list [lindex $c 0]\ [lindex $c 4]]" } } append res \n } } } } elseif {$whine} { append res "\#\# No known widget $arg\n" set code error } } } a* { ## see if we recognize it, other complain if {[regexp {(var|com|proc|widget)} \ [set types [uplevel 1 what $args]]]} { foreach type $types { if {[regexp {(var|com|proc|widget)} $type]} { append res "[uplevel 1 dump $type $args]\n" } } } else { set res "dump was unable to resolve type for \"$args\"" set code error } } default { return -code error "bad [lindex [info level 0] 0] option\ \"$type\": must be variable, command, procedure,\ or widget" } } return -code $code [string trimright $res \n] } ## idebug - interactive debugger # # idebug body ?level? # # Prints out the body of the command (if it is a procedure) at the # specified level. level defaults to the current level. # # idebug break # # Creates a breakpoint within a procedure. This will only trigger # if idebug is on and the id matches the pattern. If so, TkCon will # pop to the front with the prompt changed to an idebug prompt. You # are given the basic ability to observe the call stack an query/set # variables or execute Tcl commands at any level. A separate history # is maintained in debugging mode. # # idebug echo|{echo ?id?} ?args? # # Behaves just like "echo", but only triggers when idebug is on. # You can specify an optional id to further restrict triggering. # If no id is specified, it defaults to the name of the command # in which the call was made. # # idebug id ?id? # # Query or set the idebug id. This id is used by other idebug # methods to determine if they should trigger or not. The idebug # id can be a glob pattern and defaults to *. # # idebug off # # Turns idebug off. # # idebug on ?id? # # Turns idebug on. If 'id' is specified, it sets the id to it. # # idebug puts|{puts ?id?} args # # Behaves just like "puts", but only triggers when idebug is on. # You can specify an optional id to further restrict triggering. # If no id is specified, it defaults to the name of the command # in which the call was made. # # idebug show type ?level? ?VERBOSE? # # 'type' must be one of vars, locals or globals. This method # will output the variables/locals/globals present in a particular # level. If VERBOSE is added, then it actually 'dump's out the # values as well. 'level' defaults to the level in which this # method was called. # # idebug trace ?level? # # Prints out the stack trace from the specified level up to the top # level. 'level' defaults to the current level. # ## proc idebug {opt args} { global IDEBUG if {![info exists IDEBUG(on)]} { array set IDEBUG { on 0 id * debugging 0 } } set level [expr {[info level]-1}] switch -glob -- $opt { on { if {[llength $args]} { set IDEBUG(id) $args } return [set IDEBUG(on) 1] } off { return [set IDEBUG(on) 0] } id { if {![llength $args]} { return $IDEBUG(id) } else { return [set IDEBUG(id) $args] } } break { if {!$IDEBUG(on) || $IDEBUG(debugging) || \ ([llength $args] && \ ![string match $IDEBUG(id) $args]) || [info level]<1} { return } set IDEBUG(debugging) 1 puts stderr "idebug at level \#$level: [lindex [info level -1] 0]" set tkcon [llength [info command tkcon]] if {$tkcon} { tkcon master eval set ::tkcon::OPT(prompt2) \$::tkcon::OPT(prompt1) tkcon master eval set ::tkcon::OPT(prompt1) \$::tkcon::OPT(debugPrompt) set slave [tkcon set ::tkcon::OPT(exec)] set event [tkcon set ::tkcon::PRIV(event)] tkcon set ::tkcon::OPT(exec) [tkcon master interp create debugger] tkcon set ::tkcon::PRIV(event) 1 } set max $level while 1 { set err {} if {$tkcon} { # tkcon's overload of gets is advanced enough to not need # this, but we get a little better control this way. tkcon evalSlave set level $level tkcon prompt set line [tkcon getcommand] tkcon console mark set output end } else { puts -nonewline stderr "(level \#$level) debug > " gets stdin line while {![info complete $line]} { puts -nonewline "> " append line "\n[gets stdin]" } } if {[string match {} $line]} continue set key [lindex $line 0] if {![regexp {^([#-]?[0-9]+)} [lreplace $line 0 0] lvl]} { set lvl \#$level } set res {}; set c 0 switch -- $key { + { ## Allow for jumping multiple levels if {$level < $max} { idebug trace [incr level] $level 0 VERBOSE } } - { ## Allow for jumping multiple levels if {$level > 1} { idebug trace [incr level -1] $level 0 VERBOSE } } . { set c [catch {idebug trace $level $level 0 VERBOSE} res] } v { set c [catch {idebug show vars $lvl } res] } V { set c [catch {idebug show vars $lvl VERBOSE} res] } l { set c [catch {idebug show locals $lvl } res] } L { set c [catch {idebug show locals $lvl VERBOSE} res] } g { set c [catch {idebug show globals $lvl } res] } G { set c [catch {idebug show globals $lvl VERBOSE} res] } t { set c [catch {idebug trace 1 $max $level } res] } T { set c [catch {idebug trace 1 $max $level VERBOSE} res]} b { set c [catch {idebug body $lvl} res] } o { set res [set IDEBUG(on) [expr {!$IDEBUG(on)}]] } h - ? { puts stderr " + Move down in call stack - Move up in call stack . Show current proc name and params v Show names of variables currently in scope V Show names of variables currently in scope with values l Show names of local (transient) variables L Show names of local (transient) variables with values g Show names of declared global variables G Show names of declared global variables with values t Show a stack trace T Show a verbose stack trace b Show body of current proc o Toggle on/off any further debugging c,q Continue regular execution (Quit debugger) h,? Print this help default Evaluate line at current level (\#$level)" } c - q break default { set c [catch {uplevel \#$level $line} res] } } if {$tkcon} { tkcon set ::tkcon::PRIV(event) \ [tkcon evalSlave eval history add [list $line]\ \; history nextid] } if {$c} { puts stderr $res } elseif {[string compare {} $res]} { puts $res } } set IDEBUG(debugging) 0 if {$tkcon} { tkcon master interp delete debugger tkcon master eval set ::tkcon::OPT(prompt1) \$::tkcon::OPT(prompt2) tkcon set ::tkcon::OPT(exec) $slave tkcon set ::tkcon::PRIV(event) $event tkcon prompt } } bo* { if {[regexp {^([#-]?[0-9]+)} $args level]} { return [uplevel $level {dump c -no [lindex [info level 0] 0]}] } } t* { if {[llength $args]<2} return set min [set max [set lvl $level]] set exp {^#?([0-9]+)? ?#?([0-9]+) ?#?([0-9]+)? ?(VERBOSE)?} if {![regexp $exp $args junk min max lvl verbose]} return for {set i $max} { $i>=$min && ![catch {uplevel \#$i info level 0} info] } {incr i -1} { if {$i==$lvl} { puts -nonewline stderr "* \#$i:\t" } else { puts -nonewline stderr " \#$i:\t" } set name [lindex $info 0] if {[string compare VERBOSE $verbose] || \ ![llength [info procs $name]]} { puts $info } else { puts "proc $name {[info args $name]} { ... }" set idx 0 foreach arg [info args $name] { if {[string match args $arg]} { puts "\t$arg = [lrange $info [incr idx] end]" break } else { puts "\t$arg = [lindex $info [incr idx]]" } } } } } s* { #var, local, global set level \#$level if {![regexp {^([vgl][^ ]*) ?([#-]?[0-9]+)? ?(VERBOSE)?} \ $args junk type level verbose]} return switch -glob -- $type { v* { set vars [uplevel $level {lsort [info vars]}] } l* { set vars [uplevel $level {lsort [info locals]}] } g* { set vars [lremove [uplevel $level {info vars}] \ [uplevel $level {info locals}]] } } if {[string match VERBOSE $verbose]} { return [uplevel $level dump var -nocomplain $vars] } else { return $vars } } e* - pu* { if {[llength $opt]==1 && [catch {lindex [info level -1] 0} id]} { set id [lindex [info level 0] 0] } else { set id [lindex $opt 1] } if {$IDEBUG(on) && [string match $IDEBUG(id) $id]} { if {[string match e* $opt]} { puts [concat $args] } else { eval puts $args } } } default { return -code error "bad [lindex [info level 0] 0] option \"$opt\",\ must be: [join [lsort [list on off id break print body\ trace show puts echo]] {, }]" } } } ## observe - like trace, but not # ARGS: opt - option # name - name of variable or command ## proc observe {opt name args} { global tcl_observe switch -glob -- $opt { co* { if {[regexp {^(catch|lreplace|set|puts|for|incr|info|uplevel)$} \ $name]} { return -code error "cannot observe \"$name\":\ infinite eval loop will occur" } set old ${name}@ while {[llength [info command $old]]} { append old @ } rename $name $old set max 4 regexp {^[0-9]+} $args max ## idebug trace could be used here proc $name args " for {set i \[info level\]; set max \[expr \[info level\]-$max\]} { \$i>=\$max && !\[catch {uplevel \#\$i info level 0} info\] } {incr i -1} { puts -nonewline stderr \" \#\$i:\t\" puts \$info } uplevel \[lreplace \[info level 0\] 0 0 $old\] " set tcl_observe($name) $old } cd* { if {[info exists tcl_observe($name)] && [catch { rename $name {} rename $tcl_observe($name) $name unset tcl_observe($name) } err]} { return -code error $err } } ci* { ## What a useless method... if {[info exists tcl_observe($name)]} { set i $tcl_observe($name) set res "\"$name\" observes true command \"$i\"" while {[info exists tcl_observe($i)]} { append res "\n\"$name\" observes true command \"$i\"" set i $tcl_observe($name) } return $res } } va* - vd* { set type [lindex $args 0] set args [lrange $args 1 end] if {![regexp {^[rwu]} $type type]} { return -code error "bad [lindex [info level 0] 0] $opt type\ \"$type\", must be: read, write or unset" } if {![llength $args]} { set args observe_var } uplevel 1 [list trace $opt $name $type $args] } vi* { uplevel 1 [list trace vinfo $name] } default { return -code error "bad [lindex [info level 0] 0] option\ \"[lindex $args 0]\", must be: [join [lsort \ [list command cdelete cinfo variable vdelete vinfo]] {, }]" } } } ## observe_var - auxilary function for observing vars, called by trace ## via observe # ARGS: name - variable name # el - array element name, if any # op - operation type (rwu) ## proc observe_var {name el op} { if {[string match u $op]} { if {[string compare {} $el]} { puts "unset \"${name}($el)\"" } else { puts "unset \"$name\"" } } else { upvar 1 $name $name if {[info exists ${name}($el)]} { puts [dump v ${name}($el)] } else { puts [dump v $name] } } } ## which - tells you where a command is found # ARGS: cmd - command name # Returns: where command is found (internal / external / unknown) ## proc which cmd { ## This tries to auto-load a command if not recognized set types [uplevel 1 [list what $cmd 1]] if {[llength $types]} { set out {} foreach type $types { switch -- $type { alias { set res "$cmd: aliased to [alias $cmd]" } procedure { set res "$cmd: procedure" } command { set res "$cmd: internal command" } executable { lappend out [auto_execok $cmd] } variable { lappend out "$cmd: $type" } } if {[info exists res]} { global auto_index if {[info exists auto_index($cmd)]} { ## This tells you where the command MIGHT have come from - ## not true if the command was redefined interactively or ## existed before it had to be auto_loaded. This is just ## provided as a hint at where it MAY have come from append res " ($auto_index($cmd))" } lappend out $res unset res } } return [join $out \n] } else { return -code error "$cmd: command not found" } } ## what - tells you what a string is recognized as # ARGS: str - string to id # Returns: id types of command as list ## proc what {str {autoload 0}} { set types {} if {[llength [info commands $str]] || ($autoload && \ [auto_load $str] && [llength [info commands $str]])} { if {[lsearch -exact [interp aliases] $str] > -1} { lappend types "alias" } elseif { [llength [info procs $str]] || ([string match *::* $str] && [llength [namespace eval [namespace qualifier $str] \ info procs [namespace tail $str]]]) } { lappend types "procedure" } else { lappend types "command" } } if {[llength [uplevel 1 info vars $str]]} { upvar 1 $str var if {[array exists var]} { lappend types array variable } else { lappend types scalar variable } } if {[file isdirectory $str]} { lappend types "directory" } if {[file isfile $str]} { lappend types "file" } if {[llength [info commands winfo]] && [winfo exists $str]} { lappend types "widget" } if {[string compare {} [auto_execok $str]]} { lappend types "executable" } return $types } ## dir - directory list # ARGS: args - names/glob patterns of directories to list # OPTS: -all - list hidden files as well (Unix dot files) # -long - list in full format "permissions size date filename" # -full - displays / after directories and link paths for links # Returns: a directory listing ## proc dir {args} { array set s { all 0 full 0 long 0 0 --- 1 --x 2 -w- 3 -wx 4 r-- 5 r-x 6 rw- 7 rwx } while {[string match \-* [lindex $args 0]]} { set str [lindex $args 0] set args [lreplace $args 0 0] switch -glob -- $str { -a* {set s(all) 1} -f* {set s(full) 1} -l* {set s(long) 1} -- break default { return -code error "unknown option \"$str\",\ should be one of: -all, -full, -long" } } } set sep [string trim [file join . .] .] if {![llength $args]} { set args . } if {$::tcl_version >= 8.3} { # Newer glob args allow safer dir processing. The user may still # want glob chars, but really only for file matching. foreach arg $args { if {[file isdirectory $arg]} { if {$s(all)} { lappend out [list $arg [lsort \ [glob -nocomplain -directory $arg .* *]]] } else { lappend out [list $arg [lsort \ [glob -nocomplain -directory $arg *]]] } } else { set dir [file dirname $arg] lappend out [list $dir$sep [lsort \ [glob -nocomplain -directory $dir [file tail $arg]]]] } } } else { foreach arg $args { if {[file isdirectory $arg]} { set arg [string trimright $arg $sep]$sep if {$s(all)} { lappend out [list $arg [lsort [glob -nocomplain -- $arg.* $arg*]]] } else { lappend out [list $arg [lsort [glob -nocomplain -- $arg*]]] } } else { lappend out [list [file dirname $arg]$sep \ [lsort [glob -nocomplain -- $arg]]] } } } if {$s(long)} { set old [clock scan {1 year ago}] set fmt "%s%9d %s %s\n" foreach o $out { set d [lindex $o 0] append res $d:\n foreach f [lindex $o 1] { file lstat $f st set f [file tail $f] if {$s(full)} { switch -glob $st(type) { d* { append f $sep } l* { append f "@ -> [file readlink $d$sep$f]" } default { if {[file exec $d$sep$f]} { append f * } } } } if {[string match file $st(type)]} { set mode - } else { set mode [string index $st(type) 0] } foreach j [split [format %03o [expr {$st(mode)&0777}]] {}] { append mode $s($j) } if {$st(mtime)>$old} { set cfmt {%b %d %H:%M} } else { set cfmt {%b %d %Y} } append res [format $fmt $mode $st(size) \ [clock format $st(mtime) -format $cfmt] $f] } append res \n } } else { foreach o $out { set d [lindex $o 0] append res "$d:\n" set i 0 foreach f [lindex $o 1] { if {[string len [file tail $f]] > $i} { set i [string len [file tail $f]] } } set i [expr {$i+2+$s(full)}] set j 80 ## This gets the number of cols in the tkcon console widget if {[llength [info commands tkcon]]} { set j [expr {[tkcon master set ::tkcon::OPT(cols)]/$i}] } set k 0 foreach f [lindex $o 1] { set f [file tail $f] if {$s(full)} { switch -glob [file type $d$sep$f] { d* { append f $sep } l* { append f @ } default { if {[file exec $d$sep$f]} { append f * } } } } append res [format "%-${i}s" $f] if {$j == 0 || [incr k]%$j == 0} { set res [string trimright $res]\n } } append res \n\n } } return [string trimright $res] } interp alias {} ::ls {} ::dir -full ## lremove - remove items from a list # OPTS: # -all remove all instances of each item # -glob remove all instances matching glob pattern # -regexp remove all instances matching regexp pattern # ARGS: l a list to remove items from # args items to remove (these are 'join'ed together) ## proc lremove {args} { array set opts {-all 0 pattern -exact} while {[string match -* [lindex $args 0]]} { switch -glob -- [lindex $args 0] { -a* { set opts(-all) 1 } -g* { set opts(pattern) -glob } -r* { set opts(pattern) -regexp } -- { set args [lreplace $args 0 0]; break } default {return -code error "unknown option \"[lindex $args 0]\""} } set args [lreplace $args 0 0] } set l [lindex $args 0] foreach i [join [lreplace $args 0 0]] { if {[set ix [lsearch $opts(pattern) $l $i]] == -1} continue set l [lreplace $l $ix $ix] if {$opts(-all)} { while {[set ix [lsearch $opts(pattern) $l $i]] != -1} { set l [lreplace $l $ix $ix] } } } return $l } if {!$::tkcon::PRIV(WWW)} {; ## Unknown changed to get output into tkcon window # unknown: # Invoked automatically whenever an unknown command is encountered. # Works through a list of "unknown handlers" that have been registered # to deal with unknown commands. Extensions can integrate their own # handlers into the 'unknown' facility via 'unknown_handler'. # # If a handler exists that recognizes the command, then it will # take care of the command action and return a valid result or a # Tcl error. Otherwise, it should return "-code continue" (=2) # and responsibility for the command is passed to the next handler. # # Arguments: # args - A list whose elements are the words of the original # command, including the command name. proc unknown args { global unknown_handler_order unknown_handlers errorInfo errorCode # # Be careful to save error info now, and restore it later # for each handler. Some handlers generate their own errors # and disrupt handling. # set savedErrorCode $errorCode set savedErrorInfo $errorInfo if {![info exists unknown_handler_order] || \ ![info exists unknown_handlers]} { set unknown_handlers(tcl) tcl_unknown set unknown_handler_order tcl } foreach handler $unknown_handler_order { set status [catch {uplevel 1 $unknown_handlers($handler) $args} result] if {$status == 1} { # # Strip the last five lines off the error stack (they're # from the "uplevel" command). # set new [split $errorInfo \n] set new [join [lrange $new 0 [expr {[llength $new]-6}]] \n] return -code $status -errorcode $errorCode \ -errorinfo $new $result } elseif {$status != 4} { return -code $status $result } set errorCode $savedErrorCode set errorInfo $savedErrorInfo } set name [lindex $args 0] return -code error "invalid command name \"$name\"" } # tcl_unknown: # Invoked when a Tcl command is invoked that doesn't exist in the # interpreter: # # 1. See if the autoload facility can locate the command in a # Tcl script file. If so, load it and execute it. # 2. If the command was invoked interactively at top-level: # (a) see if the command exists as an executable UNIX program. # If so, "exec" the command. # (b) see if the command requests csh-like history substitution # in one of the common forms !!, !, or ^old^new. If # so, emulate csh's history substitution. # (c) see if the command is a unique abbreviation for another # command. If so, invoke the command. # # Arguments: # args - A list whose elements are the words of the original # command, including the command name. proc tcl_unknown args { global auto_noexec auto_noload env unknown_pending tcl_interactive global errorCode errorInfo # If the command word has the form "namespace inscope ns cmd" # then concatenate its arguments onto the end and evaluate it. set cmd [lindex $args 0] if {[regexp "^namespace\[ \t\n\]+inscope" $cmd] && [llength $cmd] == 4} { set arglist [lrange $args 1 end] set ret [catch {uplevel 1 $cmd $arglist} result] if {$ret == 0} { return $result } else { return -code $ret -errorcode $errorCode $result } } # CAD tools special: # Check for commands which were renamed to tcl_(command) if {[lsearch [info commands] tcl_$cmd] >= 0} { set arglist [concat tcl_$cmd [lrange $args 1 end]] set ret [catch {eval $arglist} result] if {$ret == 0} { return $result } else { return -code $ret -errorcode $errorCode $result } } # Save the values of errorCode and errorInfo variables, since they # may get modified if caught errors occur below. The variables will # be restored just before re-executing the missing command. set savedErrorCode $errorCode set savedErrorInfo $errorInfo set name [lindex $args 0] if {![info exists auto_noload]} { # # Make sure we're not trying to load the same proc twice. # if {[info exists unknown_pending($name)]} { return -code error "self-referential recursion in \"unknown\" for command \"$name\"" } set unknown_pending($name) pending if {[llength [info args auto_load]]==1} { set ret [catch {auto_load $name} msg] } else { set ret [catch {auto_load $name [uplevel 1 {namespace current}]} msg] } unset unknown_pending($name) if {$ret} { return -code $ret -errorcode $errorCode \ "error while autoloading \"$name\": $msg" } # # Avoid problems with renaming "array"! (for tcl-based magic only) # set arraycmd array if {[lsearch [info commands] tcl_array] >= 0} {set arraycmd tcl_array} if {![$arraycmd size unknown_pending]} { unset unknown_pending } if {$msg} { set errorCode $savedErrorCode set errorInfo $savedErrorInfo set code [catch {uplevel 1 $args} msg] if {$code == 1} { # # Strip the last five lines off the error stack (they're # from the "uplevel" command). # set new [split $errorInfo \n] set new [join [lrange $new 0 [expr {[llength $new]-6}]] \n] return -code error -errorcode $errorCode \ -errorinfo $new $msg } else { return -code $code $msg } } } if {[info level] == 1 && [string match {} [info script]] \ && [info exists tcl_interactive] && $tcl_interactive} { if {![info exists auto_noexec]} { set new [auto_execok $name] if {[string compare {} $new]} { set errorCode $savedErrorCode set errorInfo $savedErrorInfo return [uplevel 1 exec $new [lrange $args 1 end]] #return [uplevel exec >&@stdout <@stdin $new [lrange $args 1 end]] } } set errorCode $savedErrorCode set errorInfo $savedErrorInfo ## ## History substitution moved into ::tkcon::EvalCmd ## set ret [catch {set cmds [info commands $name*]} msg] if {[string compare $name "::"] == 0} { set name "" } if {$ret != 0} { return -code $ret -errorcode $errorCode \ "error in unknown while checking if \"$name\" is a unique command abbreviation: $msg" } set cmds [info commands $name*] if {[llength $cmds] == 1} { return [uplevel 1 [lreplace $args 0 0 $cmds]] } if {[llength $cmds]} { if {$name == ""} { return -code error "empty command name \"\"" } else { return -code error \ "ambiguous command name \"$name\": [lsort $cmds]" } } ## We've got nothing so far ## Check and see if Tk wasn't loaded, but it appears to be a Tk cmd if {![uplevel \#0 info exists tk_version]} { lappend tkcmds bell bind bindtags button \ canvas checkbutton clipboard destroy \ entry event focus font frame grab grid image \ label listbox lower menu menubutton message \ option pack place radiobutton raise \ scale scrollbar selection send spinbox \ text tk tkwait toplevel winfo wm if {[lsearch -exact $tkcmds $name] >= 0 && \ [tkcon master tk_messageBox -icon question -parent . \ -title "Load Tk?" -type retrycancel -default retry \ -message "This appears to be a Tk command, but Tk\ has not yet been loaded. Shall I retry the command\ with loading Tk first?"] == "retry"} { return [uplevel 1 "load {} Tk; $args"] } } } return -code continue } } ; # end exclusionary code for WWW proc ::tkcon::Bindings {} { variable PRIV global tcl_platform tk_version #----------------------------------------------------------------------- # Elements of tkPriv that are used in this file: # # char - Character position on the line; kept in order # to allow moving up or down past short lines while # still remembering the desired position. # mouseMoved - Non-zero means the mouse has moved a significant # amount since the button went down (so, for example, # start dragging out a selection). # prevPos - Used when moving up or down lines via the keyboard. # Keeps track of the previous insert position, so # we can distinguish a series of ups and downs, all # in a row, from a new up or down. # selectMode - The style of selection currently underway: # char, word, or line. # x, y - Last known mouse coordinates for scanning # and auto-scanning. #----------------------------------------------------------------------- switch -glob $tcl_platform(platform) { win* { set PRIV(meta) Alt } mac* { set PRIV(meta) Command } default { set PRIV(meta) Meta } } ## Get all Text bindings into TkConsole foreach ev [bind Text] { bind TkConsole $ev [bind Text $ev] } ## We really didn't want the newline insertion bind TkConsole {} bind TkConsole <> {} bind TkConsole <> {} ## Now make all our virtual event bindings foreach {ev key} [subst -nocommand -noback { <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <$PRIV(meta)-i> <> <> <$PRIV(meta)-o> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> }] { event add $ev $key ## Make sure the specific key won't be defined bind TkConsole $key {} } ## Make the ROOT bindings bind $PRIV(root) <> exit bind $PRIV(root) <> { ::tkcon::New } bind $PRIV(root) <> { ::tkcon::Destroy } bind $PRIV(root) <> { ::tkcon::About } bind $PRIV(root) <> { ::tkcon::Help } bind $PRIV(root) <> { ::tkcon::FindBox $::tkcon::PRIV(console) } bind $PRIV(root) <> { ::tkcon::Attach {} ::tkcon::Prompt "\n" [::tkcon::CmdGet $::tkcon::PRIV(console)] } bind $PRIV(root) <> { if {[string compare {} $::tkcon::PRIV(name)]} { ::tkcon::Attach $::tkcon::PRIV(name) } else { ::tkcon::Attach Main } ::tkcon::Prompt "\n" [::tkcon::CmdGet $::tkcon::PRIV(console)] } bind $PRIV(root) <> { ::tkcon::Attach Main ::tkcon::Prompt "\n" [::tkcon::CmdGet $::tkcon::PRIV(console)] } bind $PRIV(root) <> { ::tkcon::PopupMenu %X %Y } ## Menu items need null TkConsolePost bindings to avoid the TagProc ## foreach ev [bind $PRIV(root)] { bind TkConsolePost $ev { # empty } } # ::tkcon::ClipboardKeysyms -- # This procedure is invoked to identify the keys that correspond to # the copy, cut, and paste functions for the clipboard. # # Arguments: # copy - Name of the key (keysym name plus modifiers, if any, # such as "Meta-y") used for the copy operation. # cut - Name of the key used for the cut operation. # paste - Name of the key used for the paste operation. proc ::tkcon::ClipboardKeysyms {copy cut paste} { bind TkConsole <$copy> {::tkcon::Copy %W} bind TkConsole <$cut> {::tkcon::Cut %W} bind TkConsole <$paste> {::tkcon::Paste %W} } proc ::tkcon::GetSelection {w} { if { ![catch {selection get -displayof $w -type UTF8_STRING} txt] || ![catch {selection get -displayof $w} txt] || ![catch {selection get -displayof $w -selection CLIPBOARD} txt] } { return $txt } return -code error "could not find default selection" } proc ::tkcon::Cut w { if {[string match $w [selection own -displayof $w]]} { clipboard clear -displayof $w catch { set txt [selection get -displayof $w] clipboard append -displayof $w $txt if {[$w compare sel.first >= limit]} { $w delete sel.first sel.last } } } } proc ::tkcon::Copy w { if {[string match $w [selection own -displayof $w]]} { clipboard clear -displayof $w catch { set txt [selection get -displayof $w] clipboard append -displayof $w $txt } } } proc ::tkcon::Paste w { if {![catch {GetSelection $w} txt]} { if {[$w compare insert < limit]} { $w mark set insert end } $w insert insert $txt $w see insert if {[string match *\n* $txt]} { ::tkcon::Eval $w } } } ## Redefine for TkConsole what we need ## event delete <> ::tkcon::ClipboardKeysyms bind TkConsole { catch { ::tkcon::Insert %W [::tkcon::GetSelection %W] } } bind TkConsole {+ catch { eval %W tag remove sel [%W tag nextrange prompt sel.first sel.last] eval %W tag remove sel sel.last-1c %W mark set insert sel.first } } ## binding editor needed ## binding for .tkconrc bind TkConsole <> { if {[%W compare insert > limit]} {::tkcon::Expand %W path} break } bind TkConsole <> { if {[%W compare insert > limit]} {::tkcon::Expand %W proc} } bind TkConsole <> { if {[%W compare insert > limit]} {::tkcon::Expand %W var} } bind TkConsole <> { if {[%W compare insert > limit]} {::tkcon::Expand %W} } bind TkConsole <> { if {[%W compare insert >= limit]} { ::tkcon::Insert %W \t } } bind TkConsole <> { if {[%W compare insert >= limit]} { ::tkcon::Insert %W \n } } bind TkConsole <> { ::tkcon::Eval %W } bind TkConsole { if {[llength [%W tag nextrange sel 1.0 end]] \ && [%W compare sel.first >= limit]} { %W delete sel.first sel.last } elseif {[%W compare insert >= limit]} { %W delete insert %W see insert } } bind TkConsole { if {[llength [%W tag nextrange sel 1.0 end]] \ && [%W compare sel.first >= limit]} { %W delete sel.first sel.last } elseif {[%W compare insert != 1.0] && [%W compare insert > limit]} { %W delete insert-1c %W see insert } } bind TkConsole [bind TkConsole ] bind TkConsole { ::tkcon::Insert %W %A } bind TkConsole { if {[%W compare {limit linestart} == {insert linestart}]} { tkTextSetCursor %W limit } else { tkTextSetCursor %W {insert linestart} } } bind TkConsole [bind TkConsole ] bind TkConsole { if {[%W compare insert < limit]} break %W delete insert } bind TkConsole { if {[%W compare insert < limit]} break if {[%W compare insert == {insert lineend}]} { %W delete insert } else { %W delete insert {insert lineend} } } bind TkConsole <> { ## Clear console buffer, without losing current command line input set ::tkcon::PRIV(tmp) [::tkcon::CmdGet %W] clear ::tkcon::Prompt {} $::tkcon::PRIV(tmp) } bind TkConsole <> { if {[%W compare {insert linestart} != {limit linestart}]} { tkTextSetCursor %W [tkTextUpDownLine %W -1] } else { ::tkcon::Event -1 } } bind TkConsole <> { if {[%W compare {insert linestart} != {end-1c linestart}]} { tkTextSetCursor %W [tkTextUpDownLine %W 1] } else { ::tkcon::Event 1 } } bind TkConsole <> { ::tkcon::Event 1 } bind TkConsole <> { ::tkcon::Event -1 } bind TkConsole <> { ::tkcon::Event -1 [::tkcon::CmdGet %W] } bind TkConsole <> { ::tkcon::Event 1 [::tkcon::CmdGet %W] } bind TkConsole <> { ## Transpose current and previous chars if {[%W compare insert > "limit+1c"]} { tkTextTranspose %W } } bind TkConsole <> { ## Clear command line (Unix shell staple) %W delete limit end } bind TkConsole <> { ## Save command buffer (swaps with current command) set ::tkcon::PRIV(tmp) $::tkcon::PRIV(cmdsave) set ::tkcon::PRIV(cmdsave) [::tkcon::CmdGet %W] if {[string match {} $::tkcon::PRIV(cmdsave)]} { set ::tkcon::PRIV(cmdsave) $::tkcon::PRIV(tmp) } else { %W delete limit end-1c } ::tkcon::Insert %W $::tkcon::PRIV(tmp) %W see end } catch {bind TkConsole { tkTextScrollPages %W -1 }} catch {bind TkConsole { tkTextScrollPages %W -1 }} catch {bind TkConsole { tkTextScrollPages %W 1 }} catch {bind TkConsole { tkTextScrollPages %W 1 }} bind TkConsole <$PRIV(meta)-d> { if {[%W compare insert >= limit]} { %W delete insert {insert wordend} } } bind TkConsole <$PRIV(meta)-BackSpace> { if {[%W compare {insert -1c wordstart} >= limit]} { %W delete {insert -1c wordstart} insert } } bind TkConsole <$PRIV(meta)-Delete> { if {[%W compare insert >= limit]} { %W delete insert {insert wordend} } } bind TkConsole { if { (!$tkPriv(mouseMoved) || $tk_strictMotif) && ![catch {::tkcon::GetSelection %W} ::tkcon::PRIV(tmp)] } { if {[%W compare @%x,%y < limit]} { %W insert end $::tkcon::PRIV(tmp) } else { %W insert @%x,%y $::tkcon::PRIV(tmp) } if {[string match *\n* $::tkcon::PRIV(tmp)]} {::tkcon::Eval %W} } } ## ## End TkConsole bindings ## ## ## Bindings for doing special things based on certain keys ## bind TkConsolePost { if {$::tkcon::OPT(lightbrace) && $::tkcon::OPT(blinktime)>99 && \ [string compare \\ [%W get insert-2c]]} { ::tkcon::MatchPair %W \( \) limit } set ::tkcon::PRIV(StatusCursor) [%W index insert] } bind TkConsolePost { if {$::tkcon::OPT(lightbrace) && $::tkcon::OPT(blinktime)>99 && \ [string compare \\ [%W get insert-2c]]} { ::tkcon::MatchPair %W \[ \] limit } set ::tkcon::PRIV(StatusCursor) [%W index insert] } bind TkConsolePost { if {$::tkcon::OPT(lightbrace) && $::tkcon::OPT(blinktime)>99 && \ [string compare \\ [%W get insert-2c]]} { ::tkcon::MatchPair %W \{ \} limit } set ::tkcon::PRIV(StatusCursor) [%W index insert] } bind TkConsolePost { if {$::tkcon::OPT(lightbrace) && $::tkcon::OPT(blinktime)>99 && \ [string compare \\ [%W get insert-2c]]} { ::tkcon::MatchQuote %W limit } set ::tkcon::PRIV(StatusCursor) [%W index insert] } bind TkConsolePost { if {$::tkcon::OPT(lightcmd) && [string compare {} %A]} { ::tkcon::TagProc %W } set ::tkcon::PRIV(StatusCursor) [%W index insert] } bind TkConsolePost { set ::tkcon::PRIV(StatusCursor) [%W index insert] } bind TkConsolePost { set ::tkcon::PRIV(StatusCursor) [%W index insert] } } ## # ::tkcon::PopupMenu - what to do when the popup menu is requested ## proc ::tkcon::PopupMenu {X Y} { variable PRIV set w $PRIV(console) if {[string compare $w [winfo containing $X $Y]]} { tk_popup $PRIV(popup) $X $Y return } set x [expr {$X-[winfo rootx $w]}] set y [expr {$Y-[winfo rooty $w]}] if {[llength [set tags [$w tag names @$x,$y]]]} { if {[lsearch -exact $tags "proc"] >= 0} { lappend type "proc" foreach {first last} [$w tag prevrange proc @$x,$y] { set word [$w get $first $last]; break } } if {[lsearch -exact $tags "var"] >= 0} { lappend type "var" foreach {first last} [$w tag prevrange var @$x,$y] { set word [$w get $first $last]; break } } } if {![info exists type]} { set exp "(^|\[^\\\\\]\[ \t\n\r\])" set exp2 "\[\[\\\\\\?\\*\]" set i [$w search -backwards -regexp $exp @$x,$y "@$x,$y linestart"] if {[string compare {} $i]} { if {![string match *.0 $i]} {append i +2c} if {[string compare {} \ [set j [$w search -regexp $exp $i "$i lineend"]]]} { append j +1c } else { set j "$i lineend" } regsub -all $exp2 [$w get $i $j] {\\\0} word set word [string trim $word {\"$[]{}',?#*}] if {[llength [EvalAttached [list info commands $word]]]} { lappend type "proc" } if {[llength [EvalAttached [list info vars $word]]]} { lappend type "var" } if {[EvalAttached [list file isfile $word]]} { lappend type "file" } } } if {![info exists type] || ![info exists word]} { tk_popup $PRIV(popup) $X $Y return } $PRIV(context) delete 0 end $PRIV(context) add command -label "$word" -state disabled $PRIV(context) add separator set app [Attach] if {[lsearch $type proc] != -1} { $PRIV(context) add command -label "View Procedure" \ -command [list edit -attach $app -type proc -- $word] } if {[lsearch $type var] != -1} { $PRIV(context) add command -label "View Variable" \ -command [list edit -attach $app -type var -- $word] } if {[lsearch $type file] != -1} { $PRIV(context) add command -label "View File" \ -command [list edit -attach $app -type file -- $word] } tk_popup $PRIV(context) $X $Y } ## ::tkcon::TagProc - tags a procedure in the console if it's recognized ## This procedure is not perfect. However, making it perfect wastes ## too much CPU time... ## proc ::tkcon::TagProc w { set exp "\[^\\\\\]\[\[ \t\n\r\;{}\"\$\]" set i [$w search -backwards -regexp $exp insert-1c limit-1c] if {[string compare {} $i]} {append i +2c} else {set i limit} regsub -all "\[\[\\\\\\?\\*\]" [$w get $i "insert-1c wordend"] {\\\0} c if {[llength [EvalAttached [list info commands $c]]]} { $w tag add proc $i "insert-1c wordend" } else { $w tag remove proc $i "insert-1c wordend" } if {[llength [EvalAttached [list info vars $c]]]} { $w tag add var $i "insert-1c wordend" } else { $w tag remove var $i "insert-1c wordend" } } ## ::tkcon::MatchPair - blinks a matching pair of characters ## c2 is assumed to be at the text index 'insert'. ## This proc is really loopy and took me an hour to figure out given ## all possible combinations with escaping except for escaped \'s. ## It doesn't take into account possible commenting... Oh well. If ## anyone has something better, I'd like to see/use it. This is really ## only efficient for small contexts. # ARGS: w - console text widget # c1 - first char of pair # c2 - second char of pair # Calls: ::tkcon::Blink ## proc ::tkcon::MatchPair {w c1 c2 {lim 1.0}} { if {[string compare {} [set ix [$w search -back $c1 insert $lim]]]} { while { [string match {\\} [$w get $ix-1c]] && [string compare {} [set ix [$w search -back $c1 $ix-1c $lim]]] } {} set i1 insert-1c while {[string compare {} $ix]} { set i0 $ix set j 0 while {[string compare {} [set i0 [$w search $c2 $i0 $i1]]]} { append i0 +1c if {[string match {\\} [$w get $i0-2c]]} continue incr j } if {!$j} break set i1 $ix while {$j && [string compare {} \ [set ix [$w search -back $c1 $ix $lim]]]} { if {[string match {\\} [$w get $ix-1c]]} continue incr j -1 } } if {[string match {} $ix]} { set ix [$w index $lim] } } else { set ix [$w index $lim] } if {$::tkcon::OPT(blinkrange)} { Blink $w $ix [$w index insert] } else { Blink $w $ix $ix+1c [$w index insert-1c] [$w index insert] } } ## ::tkcon::MatchQuote - blinks between matching quotes. ## Blinks just the quote if it's unmatched, otherwise blinks quoted string ## The quote to match is assumed to be at the text index 'insert'. # ARGS: w - console text widget # Calls: ::tkcon::Blink ## proc ::tkcon::MatchQuote {w {lim 1.0}} { set i insert-1c set j 0 while {[string compare [set i [$w search -back \" $i $lim]] {}]} { if {[string match {\\} [$w get $i-1c]]} continue if {!$j} {set i0 $i} incr j } if {$j&1} { if {$::tkcon::OPT(blinkrange)} { Blink $w $i0 [$w index insert] } else { Blink $w $i0 $i0+1c [$w index insert-1c] [$w index insert] } } else { Blink $w [$w index insert-1c] [$w index insert] } } ## ::tkcon::Blink - blinks between n index pairs for a specified duration. # ARGS: w - console text widget # i1 - start index to blink region # i2 - end index of blink region # dur - duration in usecs to blink for # Outputs: blinks selected characters in $w ## proc ::tkcon::Blink {w args} { eval [list $w tag add blink] $args after $::tkcon::OPT(blinktime) [list $w] tag remove blink $args return } ## ::tkcon::Insert ## Insert a string into a text console at the point of the insertion cursor. ## If there is a selection in the text, and it covers the point of the ## insertion cursor, then delete the selection before inserting. # ARGS: w - text window in which to insert the string # s - string to insert (usually just a single char) # Outputs: $s to text widget ## proc ::tkcon::Insert {w s} { if {[string match {} $s] || [string match disabled [$w cget -state]]} { return } if {[$w comp insert < limit]} { $w mark set insert end } if {[llength [$w tag ranges sel]] && \ [$w comp sel.first <= insert] && [$w comp sel.last >= insert]} { $w delete sel.first sel.last } $w insert insert $s $w see insert } ## ::tkcon::Expand - # ARGS: w - text widget in which to expand str # type - type of expansion (path / proc / variable) # Calls: ::tkcon::Expand(Pathname|Procname|Variable) # Outputs: The string to match is expanded to the longest possible match. # If ::tkcon::OPT(showmultiple) is non-zero and the user longest # match equaled the string to expand, then all possible matches # are output to stdout. Triggers bell if no matches are found. # Returns: number of matches found ## proc ::tkcon::Expand {w {type ""}} { set exp "\[^\\\\\]\[\[ \t\n\r\\\{\"$\]" set tmp [$w search -backwards -regexp $exp insert-1c limit-1c] if {[string compare {} $tmp]} {append tmp +2c} else {set tmp limit} if {[$w compare $tmp >= insert]} return set str [$w get $tmp insert] switch -glob $type { pa* { set res [ExpandPathname $str] } pr* { set res [ExpandProcname $str] } v* { set res [ExpandVariable $str] } default { set res {} foreach t $::tkcon::OPT(expandorder) { if {![catch {Expand$t $str} res] && \ [string compare {} $res]} break } } } set len [llength $res] if {$len} { $w delete $tmp insert $w insert $tmp [lindex $res 0] if {$len > 1} { if {$::tkcon::OPT(showmultiple) && \ ![string compare [lindex $res 0] $str]} { puts stdout [lsort [lreplace $res 0 0]] } } } else { bell } return [incr len -1] } ## ::tkcon::ExpandPathname - expand a file pathname based on $str ## This is based on UNIX file name conventions # ARGS: str - partial file pathname to expand # Calls: ::tkcon::ExpandBestMatch # Returns: list containing longest unique match followed by all the # possible further matches ## proc ::tkcon::ExpandPathname str { set pwd [EvalAttached pwd] # Cause a string like {C:/Program\ Files/} to become "C:/Program Files/" regsub -all {\\([][ ])} $str {\1} str if {[catch {EvalAttached [list cd [file dirname $str]]} err]} { return -code error $err } set dir [file tail $str] ## Check to see if it was known to be a directory and keep the trailing ## slash if so (file tail cuts it off) if {[string match */ $str]} { append dir / } # Create a safely glob-able name regsub -all {([][])} $dir {\\\1} safedir if {[catch {lsort [EvalAttached [list glob $safedir*]]} m]} { set match {} } else { if {[llength $m] > 1} { global tcl_platform if {[string match windows $tcl_platform(platform)]} { ## Windows is screwy because it's case insensitive set tmp [ExpandBestMatch [string tolower $m] \ [string tolower $dir]] ## Don't change case if we haven't changed the word if {[string length $dir]==[string length $tmp]} { set tmp $dir } } else { set tmp [ExpandBestMatch $m $dir] } if {[string match */* $str]} { set tmp [string trimright [file dirname $str] /]/$tmp } regsub -all {([^\\])([][ ])} $tmp {\1\\\2} tmp set match [linsert $m 0 $tmp] } else { ## This may look goofy, but it handles spaces in path names eval append match $m if {[file isdirectory $match]} {append match /} if {[string match */* $str]} { set match [string trimright [file dirname $str] /]/$match } regsub -all {([^\\])([][ ])} $match {\1\\\2} match ## Why is this one needed and the ones below aren't!! set match [list $match] } } EvalAttached [list cd $pwd] return $match } ## ::tkcon::ExpandProcname - expand a tcl proc name based on $str # ARGS: str - partial proc name to expand # Calls: ::tkcon::ExpandBestMatch # Returns: list containing longest unique match followed by all the # possible further matches ## proc ::tkcon::ExpandProcname str { set match [EvalAttached [list info commands $str*]] if {[llength $match] == 0} { set ns [EvalAttached \ "namespace children \[namespace current\] [list $str*]"] if {[llength $ns]==1} { set match [EvalAttached [list info commands ${ns}::*]] } else { set match $ns } } if {[llength $match] > 1} { regsub -all {([^\\]) } [ExpandBestMatch $match $str] {\1\\ } str set match [linsert $match 0 $str] } else { regsub -all {([^\\]) } $match {\1\\ } match } return $match } ## ::tkcon::ExpandVariable - expand a tcl variable name based on $str # ARGS: str - partial tcl var name to expand # Calls: ::tkcon::ExpandBestMatch # Returns: list containing longest unique match followed by all the # possible further matches ## proc ::tkcon::ExpandVariable str { if {[regexp {([^\(]*)\((.*)} $str junk ary str]} { ## Looks like they're trying to expand an array. set match [EvalAttached [list array names $ary $str*]] if {[llength $match] > 1} { set vars $ary\([ExpandBestMatch $match $str] foreach var $match {lappend vars $ary\($var\)} return $vars } else {set match $ary\($match\)} ## Space transformation avoided for array names. } else { set match [EvalAttached [list info vars $str*]] if {[llength $match] > 1} { regsub -all {([^\\]) } [ExpandBestMatch $match $str] {\1\\ } str set match [linsert $match 0 $str] } else { regsub -all {([^\\]) } $match {\1\\ } match } } return $match } ## ::tkcon::ExpandBestMatch2 - finds the best unique match in a list of names ## Improves upon the speed of the below proc only when $l is small ## or $e is {}. $e is extra for compatibility with proc below. # ARGS: l - list to find best unique match in # Returns: longest unique match in the list ## proc ::tkcon::ExpandBestMatch2 {l {e {}}} { set s [lindex $l 0] if {[llength $l]>1} { set i [expr {[string length $s]-1}] foreach l $l { while {$i>=0 && [string first $s $l]} { set s [string range $s 0 [incr i -1]] } } } return $s } ## ::tkcon::ExpandBestMatch - finds the best unique match in a list of names ## The extra $e in this argument allows us to limit the innermost loop a ## little further. This improves speed as $l becomes large or $e becomes long. # ARGS: l - list to find best unique match in # e - currently best known unique match # Returns: longest unique match in the list ## proc ::tkcon::ExpandBestMatch {l {e {}}} { set ec [lindex $l 0] if {[llength $l]>1} { set e [string length $e]; incr e -1 set ei [string length $ec]; incr ei -1 foreach l $l { while {$ei>=$e && [string first $ec $l]} { set ec [string range $ec 0 [incr ei -1]] } } } return $ec } # Here is a group of functions that is only used when Tkcon is # executed in a safe interpreter. It provides safe versions of # missing functions. For example: # # - "tk appname" returns "tkcon.tcl" but cannot be set # - "toplevel" is equivalent to 'frame', only it is automatically # packed. # - The 'source', 'load', 'open', 'file' and 'exit' functions are # mapped to corresponding functions in the parent interpreter. # # Further on, Tk cannot be really loaded. Still the safe 'load' # provedes a speciall case. The Tk can be divided into 4 groups, # that each has a safe handling procedure. # # - "::tkcon::SafeItem" handles commands like 'button', 'canvas' ...... # Each of these functions has the window name as first argument. # - "::tkcon::SafeManage" handles commands like 'pack', 'place', 'grid', # 'winfo', which can have multiple window names as arguments. # - "::tkcon::SafeWindow" handles all windows, such as '.'. For every # window created, a new alias is formed which also is handled by # this function. # - Other (e.g. bind, bindtag, image), which need their own function. # ## These functions courtesy Jan Nijtmans (nijtmans@nici.kun.nl) ## if {[string compare [info command tk] tk]} { proc tk {option args} { if {![string match app* $option]} { error "wrong option \"$option\": should be appname" } return "tkcon.tcl" } } if {[string compare [info command toplevel] toplevel]} { proc toplevel {name args} { eval frame $name $args pack $name } } proc ::tkcon::SafeSource {i f} { set fd [open $f r] set r [read $fd] close $fd if {[catch {interp eval $i $r} msg]} { error $msg } } proc ::tkcon::SafeOpen {i f {m r}} { set fd [open $f $m] interp transfer {} $fd $i return $fd } proc ::tkcon::SafeLoad {i f p} { global tk_version tk_patchLevel tk_library auto_path if {[string compare $p Tk]} { load $f $p $i } else { foreach command {button canvas checkbutton entry frame label listbox message radiobutton scale scrollbar spinbox text toplevel} { $i alias $command ::tkcon::SafeItem $i $command } $i alias image ::tkcon::SafeImage $i foreach command {pack place grid destroy winfo} { $i alias $command ::tkcon::SafeManage $i $command } if {[llength [info command event]]} { $i alias event ::tkcon::SafeManage $i $command } frame .${i}_dot -width 300 -height 300 -relief raised pack .${i}_dot -side left $i alias tk tk $i alias bind ::tkcon::SafeBind $i $i alias bindtags ::tkcon::SafeBindtags $i $i alias . ::tkcon::SafeWindow $i {} foreach var {tk_version tk_patchLevel tk_library auto_path} { $i eval set $var [list [set $var]] } $i eval { package provide Tk $tk_version if {[lsearch -exact $auto_path $tk_library] < 0} { lappend auto_path $tk_library } } return "" } } proc ::tkcon::SafeSubst {i a} { set arg1 "" foreach {arg value} $a { if {![string compare $arg -textvariable] || ![string compare $arg -variable]} { set newvalue "[list $i] $value" global $newvalue if {[interp eval $i info exists $value]} { set $newvalue [interp eval $i set $value] } else { catch {unset $newvalue} } $i eval trace variable $value rwu \{[list tkcon set $newvalue $i]\} set value $newvalue } elseif {![string compare $arg -command]} { set value [list $i eval $value] } lappend arg1 $arg $value } return $arg1 } proc ::tkcon::SafeItem {i command w args} { set args [::tkcon::SafeSubst $i $args] set code [catch "$command [list .${i}_dot$w] $args" msg] $i alias $w ::tkcon::SafeWindow $i $w regsub -all .${i}_dot $msg {} msg return -code $code $msg } proc ::tkcon::SafeManage {i command args} { set args1 "" foreach arg $args { if {[string match . $arg]} { set arg .${i}_dot } elseif {[string match .* $arg]} { set arg ".${i}_dot$arg" } lappend args1 $arg } set code [catch "$command $args1" msg] regsub -all .${i}_dot $msg {} msg return -code $code $msg } # # FIX: this function doesn't work yet if the binding starts with '+'. # proc ::tkcon::SafeBind {i w args} { if {[string match . $w]} { set w .${i}_dot } elseif {[string match .* $w]} { set w ".${i}_dot$w" } if {[llength $args] > 1} { set args [list [lindex $args 0] \ "[list $i] eval [list [lindex $args 1]]"] } set code [catch "bind $w $args" msg] if {[llength $args] <2 && $code == 0} { set msg [lindex $msg 3] } return -code $code $msg } proc ::tkcon::SafeImage {i option args} { set code [catch "image $option $args" msg] if {[string match cr* $option]} { $i alias $msg $msg } return -code $code $msg } proc ::tkcon::SafeBindtags {i w {tags {}}} { if {[string match . $w]} { set w .${i}_dot } elseif {[string match .* $w]} { set w ".${i}_dot$w" } set newtags {} foreach tag $tags { if {[string match . $tag]} { lappend newtags .${i}_dot } elseif {[string match .* $tag]} { lappend newtags ".${i}_dot$tag" } else { lappend newtags $tag } } if {[string match $tags {}]} { set code [catch {bindtags $w} msg] regsub -all \\.${i}_dot $msg {} msg } else { set code [catch {bindtags $w $newtags} msg] } return -code $code $msg } proc ::tkcon::SafeWindow {i w option args} { if {[string match conf* $option] && [llength $args] > 1} { set args [::tkcon::SafeSubst $i $args] } elseif {[string match itemco* $option] && [llength $args] > 2} { set args "[list [lindex $args 0]] [::tkcon::SafeSubst $i [lrange $args 1 end]]" } elseif {[string match cr* $option]} { if {[llength $args]%2} { set args "[list [lindex $args 0]] [::tkcon::SafeSubst $i [lrange $args 1 end]]" } else { set args [::tkcon::SafeSubst $i $args] } } elseif {[string match bi* $option] && [llength $args] > 2} { set args [list [lindex $args 0] [lindex $args 1] "[list $i] eval [list [lindex $args 2]]"] } set code [catch ".${i}_dot$w $option $args" msg] if {$code} { regsub -all .${i}_dot $msg {} msg } elseif {[string match conf* $option] || [string match itemco* $option]} { if {[llength $args] == 1} { switch -- $args { -textvariable - -variable { set msg "[lrange $msg 0 3] [list [lrange [lindex $msg 4] 1 end]]" } -command - updatecommand { set msg "[lrange $msg 0 3] [list [lindex [lindex $msg 4] 2]]" } } } elseif {[llength $args] == 0} { set args1 "" foreach el $msg { switch -- [lindex $el 0] { -textvariable - -variable { set el "[lrange $el 0 3] [list [lrange [lindex $el 4] 1 end]]" } -command - updatecommand { set el "[lrange $el 0 3] [list [lindex [lindex $el 4] 2]]" } } lappend args1 $el } set msg $args1 } } elseif {[string match cg* $option] || [string match itemcg* $option]} { switch -- $args { -textvariable - -variable { set msg [lrange $msg 1 end] } -command - updatecommand { set msg [lindex $msg 2] } } } elseif {[string match bi* $option]} { if {[llength $args] == 2 && $code == 0} { set msg [lindex $msg 2] } } return -code $code $msg } proc ::tkcon::RetrieveFilter {host} { variable PRIV set result {} if {[info exists PRIV(proxy)]} { if {![regexp "^(localhost|127\.0\.0\.1)" $host]} { set result [lrange [split [lindex $PRIV(proxy) 0] :] 0 1] } } return $result } proc ::tkcon::RetrieveAuthentication {} { package require Tk if {[catch {package require base64}]} { if {[catch {package require Trf}]} { error "base64 support not available" } else { set local64 "base64 -mode enc" } } else { set local64 "base64::encode" } set dlg [toplevel .auth] wm title $dlg "Authenticating Proxy Configuration" set f1 [frame ${dlg}.f1] set f2 [frame ${dlg}.f2] button $f2.b -text "OK" -command "destroy $dlg" pack $f2.b -side right label $f1.l2 -text "Username" label $f1.l3 -text "Password" entry $f1.e2 -textvariable "[namespace current]::conf_userid" entry $f1.e3 -textvariable "[namespace current]::conf_passwd" -show * grid $f1.l2 -column 0 -row 0 -sticky e grid $f1.l3 -column 0 -row 1 -sticky e grid $f1.e2 -column 1 -row 0 -sticky news grid $f1.e3 -column 1 -row 1 -sticky news grid columnconfigure $f1 1 -weight 1 pack $f2 -side bottom -fill x pack $f1 -side top -anchor n -fill both -expand 1 tkwait window $dlg set result {} if {[info exists [namespace current]::conf_userid]} { set data [subst $[namespace current]::conf_userid] append data : [subst $[namespace current]::conf_passwd] set data [$local64 $data] set result [list "Proxy-Authorization" "Basic $data"] } unset [namespace current]::conf_passwd return $result } proc ::tkcon::Retrieve {} { # A little bit'o'magic to grab the latest tkcon from CVS and # save it locally. It doesn't support proxies though... variable PRIV set defExt "" if {[string match "windows" $::tcl_platform(platform)]} { set defExt ".tcl" } set file [tk_getSaveFile -title "Save Latest tkcon to ..." \ -defaultextension $defExt \ -initialdir [file dirname $PRIV(SCRIPT)] \ -initialfile [file tail $PRIV(SCRIPT)] \ -parent $PRIV(root) \ -filetypes {{"Tcl Files" {.tcl .tk}} {"All Files" {*.*}}}] if {[string compare $file ""]} { package require http 2 set token [::http::geturl $PRIV(HEADURL) -timeout 30000] ::http::wait $token set code [catch { if {[::http::status $token] == "ok"} { set fid [open $file w] # We don't want newline mode to change fconfigure $fid -translation binary set data [::http::data $token] puts -nonewline $fid $data close $fid regexp {Id: tkcon.tcl,v (\d+\.\d+)} $data -> rcsVersion regexp {version\s+(\d+\.\d[^\n]*)} $data -> tkconVersion } } err] ::http::cleanup $token if {$code} { return -code error $err } elseif {[tk_messageBox -type yesno -icon info -parent $PRIV(root) \ -title "Retrieved tkcon v$tkconVersion, RCS $rcsVersion" \ -message "Successfully retrieved tkcon v$tkconVersion,\ RCS $rcsVersion. Shall I resource (not restart) this\ version now?"] == "yes"} { set PRIV(SCRIPT) $file set PRIV(version) $tkconVersion.$rcsVersion ::tkcon::Resource } } } ## ::tkcon::Resource - re'source's this script into current console ## Meant primarily for my development of this program. It follows ## links until the ultimate source is found. ## set ::tkcon::PRIV(SCRIPT) [info script] if {!$::tkcon::PRIV(WWW) && [string compare $::tkcon::PRIV(SCRIPT) {}]} { # we use a catch here because some wrap apps choke on 'file type' # because TclpLstat wasn't wrappable until 8.4. catch { while {[string match link [file type $::tkcon::PRIV(SCRIPT)]]} { set link [file readlink $::tkcon::PRIV(SCRIPT)] if {[string match relative [file pathtype $link]]} { set ::tkcon::PRIV(SCRIPT) \ [file join [file dirname $::tkcon::PRIV(SCRIPT)] $link] } else { set ::tkcon::PRIV(SCRIPT) $link } } catch {unset link} if {[string match relative [file pathtype $::tkcon::PRIV(SCRIPT)]]} { set ::tkcon::PRIV(SCRIPT) [file join [pwd] $::tkcon::PRIV(SCRIPT)] } } } proc ::tkcon::Resource {} { uplevel \#0 { if {[catch {source -rsrc tkcon}]} { source $::tkcon::PRIV(SCRIPT) } } Bindings InitSlave $::tkcon::OPT(exec) } ## Initialize only if we haven't yet ## if {![info exists ::tkcon::PRIV(root)] || \ ![winfo exists $::tkcon::PRIV(root)]} { ::tkcon::Init } qrouter-1.3.33/qrouter.sh.in0000755000175000001440000000300112406043443014451 0ustar timusers#!/bin/sh # # For installation, put this file (qrouter.sh) in a standard executable path. # Put startup script "qrouter.tcl" and shared library "qrouter.so" # in ${QROUTER_LIB_DIR}. # # This script starts qrouter under the Tcl interpreter, # reading commands from script qrouter.tcl which launches qrouter # and retains the Tcl interactive interpreter. # Parse for the argument "-noc[onsole]". If it exists, run qrouter # without the TkCon console. Strip this argument from the argument list. loclibdir=${QROUTER_LIB_DIR:=LIBDIR} export QROUTER_LIB_DIR QROUTER_WISH=WISH_EXE export QROUTER_WISH # Hacks for Cygwin if [ ${TERM:=""} = "cygwin" ]; then export PATH="$PATH:$loclibdir" export DISPLAY=${DISPLAY:=":0"} fi # Don't use the console if "-noc[onsole]" was specified. # Also, if "-i", "-h", or "-c" is specified, then this is # a batch-mode operation and the console should be ignored. TKCON=true for i in $@ ; do case $i in -noc*) TKCON= shift ;; -i* | -h* | -c* ) TKCON= ;; esac done if [ $TKCON ]; then exec ${loclibdir}/tkcon.tcl \ -eval "source ${loclibdir}/console.tcl" \ -slave "package require Tk; set argc $#; set argv [list $*]; \ source ${loclibdir}/qrouter.tcl" else # # Run the stand-in for wish (qrouterexec), which acts exactly like "wish" # except that it replaces ~/.wishrc with qrouter.tcl. This executable is # *only* needed when running without the console; the console itself is # capable of sourcing the startup script. # exec ${loclibdir}/qrouterexec -- $@ fi qrouter-1.3.33/lef.c0000664000175000001440000016543112575545527012761 0ustar timusers/* * lef.c -- * * This module incorporates the LEF/DEF format for standard-cell routing * route. * * Version 0.1 (September 26, 2003): LEF input handling. Includes creation * of cells from macro statements, handling of pins, ports, obstructions, and * associated geometry. * * Written by Tim Edwards, Open Circuit Design * Modified June 2011 for use with qrouter. * * It is assumed that the "route.cfg" file has been called prior to this, and * so the basic linked lists have been created. The contents of the LEF file * will override anything in the route.cfg file, allowing the route.cfg file * to contain a minimum of information, but also allowing for the possibility * that there is no LEF file for the technology, and that all such information * is in the route.cfg file. */ #include #include #include #include #include #include #include #include #include "qrouter.h" #include "node.h" #include "qconfig.h" #include "maze.h" #include "lef.h" /* ---------------------------------------------------------------------*/ /* Current line number for reading */ int lefCurrentLine; /* Information about routing layers */ LefList LefInfo; /* Gate information is in the linked list GateInfo, imported */ /*--------------------------------------------------------- * Lookup -- * Searches a table of strings to find one that matches a given * string. It's useful mostly for command lookup. * * Only the portion of a string in the table up to the first * blank character is considered significant for matching. * * Results: * If str is the same as * or an unambiguous abbreviation for one of the entries * in table, then the index of the matching entry is returned. * If str is not the same as any entry in the table, but * an abbreviation for more than one entry, * then -1 is returned. If str doesn't match any entry, then * -2 is returned. Case differences are ignored. * * NOTE: * Table entries need no longer be in alphabetical order * and they need not be lower case. The irouter command parsing * depends on these features. * * Side Effects: * None. *--------------------------------------------------------- */ int Lookup(str, table) char *str; /* Pointer to a string to be looked up */ char *(table[]); /* Pointer to an array of string pointers * which are the valid commands. * The end of * the table is indicated by a NULL string. */ { int match = -2; /* result, initialized to -2 = no match */ int pos; int ststart = 0; /* search for match */ for (pos=0; table[pos] != NULL; pos++) { char *tabc = table[pos]; char *strc = &(str[ststart]); while (*strc!='\0' && *tabc!=' ' && ((*tabc==*strc) || (isupper(*tabc) && islower(*strc) && (tolower(*tabc)== *strc))|| (islower(*tabc) && isupper(*strc) && (toupper(*tabc)== *strc)) )) { strc++; tabc++; } if (*strc=='\0') { /* entry matches */ if(*tabc==' ' || *tabc=='\0') { /* exact match - record it and terminate search */ match = pos; break; } else if (match == -2) { /* inexact match and no previous match - record this one * and continue search */ match = pos; } else { /* previous match, so string is ambiguous unless exact * match exists. Mark ambiguous for now, and continue * search. */ match = -1; } } } return(match); } /* * ---------------------------------------------------------------------------- * LookupFull -- * * Look up a string in a table of pointers to strings. The last * entry in the string table must be a NULL pointer. * This is much simpler than Lookup() in that it does not * allow abbreviations. It does, however, ignore case. * * Results: * Index of the name supplied in the table, or -1 if the name * is not found. * * Side effects: * None. * * ---------------------------------------------------------------------------- */ int LookupFull(name, table) char *name; char **table; { char **tp; for (tp = table; *tp; tp++) { if (strcmp(name, *tp) == 0) return (tp - table); else { char *sptr, *tptr; for (sptr = name, tptr = *tp; ((*sptr != '\0') && (*tptr != '\0')); sptr++, tptr++) if (toupper(*sptr) != toupper(*tptr)) break; if ((*sptr == '\0') && (*tptr == '\0')) return (tp - table); } } return (-1); } /* *------------------------------------------------------------ * * LefNextToken -- * * Move to the next token in the stream input. * If "ignore_eol" is FALSE, then the end-of-line character * "\n" will be returned as a token when encountered. * Otherwise, end-of-line will be ignored. * * Results: * Pointer to next token to parse * * Side Effects: * May read a new line from the specified file. * * Warnings: * The return result of LefNextToken will be overwritten by * subsequent calls to LefNextToken if more than one line of * input is parsed. * *------------------------------------------------------------ */ char * LefNextToken(FILE *f, u_char ignore_eol) { static char line[LEF_LINE_MAX + 2]; /* input buffer */ static char *nexttoken = NULL; /* pointer to next token */ static char *curtoken; /* pointer to current token */ static char eol_token='\n'; /* Read a new line if necessary */ if (nexttoken == NULL) { for(;;) { if (fgets(line, LEF_LINE_MAX + 1, f) == NULL) return NULL; lefCurrentLine++; curtoken = line; while (isspace(*curtoken) && (*curtoken != '\n') && (*curtoken != '\0')) curtoken++; /* skip leading whitespace */ if ((*curtoken != '#') && (*curtoken != '\n') && (*curtoken != '\0')) { nexttoken = curtoken; break; } } if (!ignore_eol) return &eol_token; } else curtoken = nexttoken; /* Find the next token; set to NULL if none (end-of-line). */ /* Treat quoted material as a single token */ if (*nexttoken == '\"') { nexttoken++; while (((*nexttoken != '\"') || (*(nexttoken - 1) == '\\')) && (*nexttoken != '\0')) { if (*nexttoken == '\n') { if (fgets(nexttoken + 1, LEF_LINE_MAX - (size_t)(nexttoken - line), f) == NULL) return NULL; } nexttoken++; /* skip all in quotes (move past current token) */ } if (*nexttoken == '\"') nexttoken++; } else { while (!isspace(*nexttoken) && (*nexttoken != '\0') && (*nexttoken != '\n')) nexttoken++; /* skip non-whitespace (move past current token) */ } /* Terminate the current token */ if (*nexttoken != '\0') *nexttoken++ = '\0'; while (isspace(*nexttoken) && (*nexttoken != '\0') && (*nexttoken != '\n')) nexttoken++; /* skip any whitespace */ if ((*nexttoken == '#') || (*nexttoken == '\n') || (*nexttoken == '\0')) nexttoken = NULL; return curtoken; } /* *------------------------------------------------------------ * * LefError -- * * Print an error message (via fprintf) giving the line * number of the input file on which the error occurred. * * Results: * None. * * Side Effects: * Prints to the output (stderr). * *------------------------------------------------------------ */ void LefError(char *fmt, ...) { static int errors = 0; va_list args; if (Verbose == 0) return; if (fmt == NULL) /* Special case: report any errors and reset */ { if (errors) { Fprintf(stdout, "LEF Read: encountered %d error%s total.\n", errors, (errors == 1) ? "" : "s"); errors = 0; } return; } if (errors < LEF_MAX_ERRORS) { Fprintf(stderr, "LEF Read, Line %d: ", lefCurrentLine); va_start(args, fmt); Vprintf(stderr, fmt, args); va_end(args); Flush(stderr); } else if (errors == LEF_MAX_ERRORS) Fprintf(stderr, "LEF Read: Further errors will not be reported.\n"); errors++; } /* *------------------------------------------------------------ * * LefParseEndStatement -- * * Check if the string passed in "lineptr" contains the * appropriate matching keyword. Sections in LEF files * should end with "END (keyword)" or "END". To check * against the latter case, "match" should be NULL. * * Results: * TRUE if the line matches the expected end statement, * FALSE if not. * * Side effects: * None. * *------------------------------------------------------------ */ u_char LefParseEndStatement(FILE *f, char *match) { char *token; int keyword, words; char *match_name[2]; match_name[0] = match; match_name[1] = NULL; token = LefNextToken(f, (match == NULL) ? FALSE : TRUE); if (token == NULL) { LefError("Bad file read while looking for END statement\n"); return FALSE; } /* END or ENDEXT */ if ((*token == '\n') && (match == NULL)) return TRUE; /* END */ else { keyword = LookupFull(token, match_name); if (keyword == 0) return TRUE; else return FALSE; } } /* *------------------------------------------------------------ * * LefSkipSection -- * * Skip to the "END" record of a LEF input section * String "section" must follow the "END" statement in * the file to be considered a match; however, if * section = NULL, then "END" must have no strings * following. * * Results: * None. * * Side Effects: * Reads input from the specified file. Prints an * error message if the expected END record cannot * be found. * *------------------------------------------------------------ */ void LefSkipSection(FILE *f, char *section) { char *token; int keyword; static char *end_section[] = { "END", "ENDEXT", NULL }; while ((token = LefNextToken(f, TRUE)) != NULL) { if ((keyword = Lookup(token, end_section)) == 0) { if (LefParseEndStatement(f, section)) return; } else if (keyword == 1) { if (!strcmp(section, "BEGINEXT")) return; } } LefError("Section %s has no END record!\n", section); return; } /* *------------------------------------------------------------ * * lefFindCell -- * * "name" is the name of the cell to search for. * Returns the GATE entry for the cell from the GateInfo * list. * *------------------------------------------------------------ */ GATE lefFindCell(char *name) { GATE gateginfo; for (gateginfo = GateInfo; gateginfo; gateginfo = gateginfo->next) { if (!strcasecmp(gateginfo->gatename, name)) return gateginfo; } return (GATE)NULL; } /* *------------------------------------------------------------ * * LefLower -- * * Convert a token in a LEF or DEF file to all-lowercase. * *------------------------------------------------------------ */ char * LefLower(char *token) { char *tptr; for (tptr = token; *tptr != '\0'; tptr++) *tptr = tolower(*tptr); return token; } /* *------------------------------------------------------------ * LefRedefined -- * * In preparation for redefining a LEF layer, we need * to first check if there are multiple names associated * with the lefLayer entry. If so, split the entry into * two copies, so that the redefinition doesn't affect * the other LEF names. * * Results: * Pointer to a lefLayer, which may or may not be the * same one presented to the subroutine. * * Side Effects: * May add an entry to the list of LEF layers. * *------------------------------------------------------------ */ LefList LefRedefined(LefList lefl, char *redefname) { LefList slef, newlefl; char *altName; int records; DSEG drect; /* check if more than one entry points to the same */ /* lefLayer record. If so, we will also record the */ /* name of the first type that is not the same as */ /* "redefname". */ records = 0; altName = NULL; for (slef = LefInfo; slef; slef = slef->next) { if (slef == lefl) records++; if (altName == NULL) if (strcmp(slef->lefName, redefname)) altName = (char *)slef->lefName; } if (records == 1) { /* Only one name associated with the record, so */ /* just clear all the allocated information. */ while (lefl->info.via.lr) { drect = lefl->info.via.lr->next; free(lefl->info.via.lr); lefl->info.via.lr = drect; } newlefl = lefl; } else { slef = LefFindLayer(redefname); newlefl = (LefList)malloc(sizeof(lefLayer)); newlefl->lefName = strdup(newlefl->lefName); newlefl->next = LefInfo; LefInfo = newlefl; /* If the canonical name of the original entry */ /* is "redefname", then change it. */ if (!strcmp(slef->lefName, redefname)) if (altName != NULL) slef->lefName = altName; } newlefl->type = -1; newlefl->obsType = -1; newlefl->info.via.area.x1 = 0.0; newlefl->info.via.area.x2 = 0.0; newlefl->info.via.area.y1 = 0.0; newlefl->info.via.area.y2 = 0.0; newlefl->info.via.area.layer = -1; newlefl->info.via.cell = (GATE)NULL; newlefl->info.via.lr = (DSEG)NULL; return newlefl; } /* *------------------------------------------------------------ * Find a layer record in the list of layers *------------------------------------------------------------ */ LefList LefFindLayer(char *token) { LefList lefl, rlefl; if (token == NULL) return NULL; rlefl = (LefList)NULL; for (lefl = LefInfo; lefl; lefl = lefl->next) { if (!strcmp(lefl->lefName, token)) { rlefl = lefl; break; } } return rlefl; } /* *------------------------------------------------------------ * Find a layer record in the list of layers, by layer number *------------------------------------------------------------ */ LefList LefFindLayerByNum(int layer) { LefList lefl, rlefl; rlefl = (LefList)NULL; for (lefl = LefInfo; lefl; lefl = lefl->next) { if (lefl->type == layer) { rlefl = lefl; break; } } return rlefl; } /* *------------------------------------------------------------ * Find a layer record in the list of layers, and return the * layer number. *------------------------------------------------------------ */ int LefFindLayerNum(char *token) { LefList lefl; lefl = LefFindLayer(token); if (lefl) return lefl->type; else return -1; } /* *--------------------------------------------------------------- * Find the maximum routing layer number defined by the LEF file *--------------------------------------------------------------- */ int LefGetMaxLayer() { int maxlayer = -1; LefList lefl; for (lefl = LefInfo; lefl; lefl = lefl->next) { if (lefl->type > maxlayer) maxlayer = lefl->type; } return (maxlayer + 1); } /* *------------------------------------------------------------ * Return the route keepout area, defined as the route space * plus 1/2 the route width. This is the distance outward * from an obstruction edge within which one cannot place a * route. * * If no route layer is defined, then we pick up the value * from information in the route.cfg file (if any). Here * we define it as the route pitch less 1/2 the route width, * which is the same as above if the route pitch has been * chosen for minimum spacing. * * If all else fails, return zero. *------------------------------------------------------------ */ double LefGetRouteKeepout(int layer) { LefList lefl; double dist; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { return lefl->info.route.width / 2.0 + lefl->info.route.spacing->spacing; } } return MIN(PitchX[layer], PitchY[layer]) - PathWidth[layer] / 2.0; } /* *------------------------------------------------------------ * Similar routine to the above. Return the route width for * a route layer. Return value in microns. If there is no * LEF file information about the route width, then return * half of the minimum route pitch. *------------------------------------------------------------ */ double LefGetRouteWidth(int layer) { LefList lefl; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { return lefl->info.route.width; } } return MIN(PitchX[layer], PitchY[layer]) / 2.0; } /* *------------------------------------------------------------ * Similar routine to the above. Return the route offset for * a route layer. Return value in microns. If there is no * LEF file information about the route offset, then return * half of the minimum route pitch. *------------------------------------------------------------ */ double LefGetRouteOffset(int layer) { LefList lefl; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { return lefl->info.route.offset; } } return MIN(PitchX[layer], PitchY[layer]) / 2.0; } /* *------------------------------------------------------------ * Determine and return the width of a via. The first layer * is the base (lower) layer of the via (e.g., layer 0, or * metal1, for via12). The second layer is the layer for * which we want the width rule (e.g., 0 or 1, for metal1 * or metal2). If dir = 0, return the side-to-side width, * otherwise, return the top-to-bottom width. This accounts * for non-square vias. * * Note that Via rectangles are stored with x2 dimensions * because the center can be on a half-grid position; so, * return half the value obtained. * * To-do: Differentiate between X and Y vias when doing * checkerboard via patterning. *------------------------------------------------------------ */ double LefGetViaWidth(int base, int layer, int dir) { DSEG lrect; LefList lefl; double width; lefl = LefFindLayer(ViaX[base]); if (!lefl) { if (base == Num_layers) lefl = LefFindLayer(ViaX[base - 1]); } if (lefl) { if (lefl->lefClass == CLASS_VIA) { if (lefl->info.via.area.layer == layer) { if (dir) width = lefl->info.via.area.y2 - lefl->info.via.area.y1; else width = lefl->info.via.area.x2 - lefl->info.via.area.x1; return width / 2.0; } for (lrect = lefl->info.via.lr; lrect; lrect = lrect->next) { if (lrect->layer == layer) { if (dir) width = lrect->y2 - lrect->y1; else width = lrect->x2 - lrect->x1; return width / 2.0; } } } } return MIN(PitchX[layer], PitchY[layer]) / 2.0; // Best guess } /* *------------------------------------------------------------ * And another such routine, for route spacing (minimum width) *------------------------------------------------------------ */ double LefGetRouteSpacing(int layer) { LefList lefl; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { return lefl->info.route.spacing->spacing; } } return MIN(PitchX[layer], PitchY[layer]) / 2.0; } /* *------------------------------------------------------------ * Find route spacing to a metal layer of specific width *------------------------------------------------------------ */ double LefGetRouteWideSpacing(int layer, double width) { LefList lefl; lefSpacingRule *srule; double spacing; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { // Prepare a default in case of bad values spacing = lefl->info.route.spacing->spacing; for (srule = lefl->info.route.spacing; srule; srule = srule->next) { if (srule->width > width) break; spacing = srule->spacing; } return spacing; } } return MIN(PitchX[layer], PitchY[layer]) / 2.0; } /* *------------------------------------------------------------ * Get the route pitch for a given layer *------------------------------------------------------------ */ double LefGetRoutePitch(int layer) { LefList lefl; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { return lefl->info.route.pitch; } } return MIN(PitchX[layer], PitchY[layer]); } /* *------------------------------------------------------------ * Get the route name for a given layer *------------------------------------------------------------ */ char * LefGetRouteName(int layer) { LefList lefl; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { return lefl->lefName; } } return NULL; } /* *------------------------------------------------------------ * Get the route orientation for the given layer, * where the result is 1 for horizontal, 0 for vertical, and * -1 if the layer is not found. *------------------------------------------------------------ */ int LefGetRouteOrientation(int layer) { LefList lefl; lefl = LefFindLayerByNum(layer); if (lefl) { if (lefl->lefClass == CLASS_ROUTE) { return (int)lefl->info.route.hdirection; } } return -1; } /* *------------------------------------------------------------ * LefReadLayers -- * * Read a LEF "LAYER" record from the file. * If "obstruct" is TRUE, returns the layer mapping * for obstruction geometry as defined in the * technology file (if it exists), and up to two * types are returned (the second in the 3rd argument * pointer). * * Results: * Returns layer number or -1 if no matching type is found. * * Side Effects: * Reads input from file f; * *------------------------------------------------------------ */ int LefReadLayers(f, obstruct, lreturn) FILE *f; u_char obstruct; int *lreturn; { char *token; int curlayer = -1; LefList lefl = NULL; token = LefNextToken(f, TRUE); if (*token == ';') { LefError("Bad Layer statement\n"); return -1; } else { lefl = LefFindLayer(token); if (lefl) { if (obstruct) { /* Use the obstruction type, if it is defined */ curlayer = lefl->obsType; if ((curlayer < 0) && (lefl->lefClass != CLASS_IGNORE)) curlayer = lefl->type; else if (lefl->lefClass == CLASS_VIA) if (lreturn) *lreturn = lefl->info.via.obsType; } else { if (lefl->lefClass != CLASS_IGNORE) curlayer = lefl->type; } } if ((curlayer < 0) && ((!lefl) || (lefl->lefClass != CLASS_IGNORE))) { LefError("Don't know how to parse layer \"%s\"\n", token); } } return curlayer; } /* *------------------------------------------------------------ * LefReadLayer -- * * Read a LEF "LAYER" record from the file. * If "obstruct" is TRUE, returns the layer mapping * for obstruction geometry as defined in the * technology file (if it exists). * * Results: * Returns a layer number or -1 if no match is found. * * Side Effects: * Reads input from file f; * *------------------------------------------------------------ */ int LefReadLayer(FILE *f, u_char obstruct) { return LefReadLayers(f, obstruct, (int *)NULL); } /* *------------------------------------------------------------ * LefReadRect -- * * Read a LEF "RECT" record from the file, and * return a Rect in micron coordinates. * * Results: * Returns a pointer to a Rect containing the micron * coordinates, or NULL if an error occurred. * * Side Effects: * Reads input from file f; * * Note: * LEF/DEF does NOT define a RECT record as having (...) * pairs, only routes. However, at least one DEF file * contains this syntax, so it is checked. * *------------------------------------------------------------ */ DSEG LefReadRect(FILE *f, int curlayer, float oscale) { char *token; float llx, lly, urx, ury; static struct dseg_ paintrect; u_char needMatch = FALSE; token = LefNextToken(f, TRUE); if (*token == '(') { token = LefNextToken(f, TRUE); needMatch = TRUE; } if (!token || sscanf(token, "%f", &llx) != 1) goto parse_error; token = LefNextToken(f, TRUE); if (!token || sscanf(token, "%f", &lly) != 1) goto parse_error; token = LefNextToken(f, TRUE); if (needMatch) { if (*token != ')') goto parse_error; else token = LefNextToken(f, TRUE); needMatch = FALSE; } if (*token == '(') { token = LefNextToken(f, TRUE); needMatch = TRUE; } if (!token || sscanf(token, "%f", &urx) != 1) goto parse_error; token = LefNextToken(f, TRUE); if (!token || sscanf(token, "%f", &ury) != 1) goto parse_error; if (needMatch) { token = LefNextToken(f, TRUE); if (*token != ')') goto parse_error; } if (curlayer < 0) { /* Issue warning but keep geometry with negative layer number */ LefError("No layer defined for RECT.\n"); } /* Scale coordinates (microns to centimicrons) */ paintrect.x1 = llx / oscale; paintrect.y1 = lly / oscale; paintrect.x2 = urx / oscale; paintrect.y2 = ury / oscale; paintrect.layer = curlayer; return (&paintrect); parse_error: LefError("Bad port geometry: RECT requires 4 values.\n"); return (DSEG)NULL; } /* *------------------------------------------------------------ * Support routines for polygon reading *------------------------------------------------------------ */ #define HEDGE 0 /* Horizontal edge */ #define REDGE 1 /* Rising edge */ #define FEDGE -1 /* Falling edge */ /* *------------------------------------------------------------ * lefLowX --- * * Sort routine to find the lowest X coordinate between * two DPOINT structures passed from qsort() *------------------------------------------------------------ */ int lefLowX(DPOINT *a, DPOINT *b) { DPOINT p = *a; DPOINT q = *b; if (p->x < q->x) return (-1); if (p->x > q->x) return (1); return (0); } /* *------------------------------------------------------------ * lefLowY --- * * Sort routine to find the lowest Y coordinate between * two DPOINT structures passed from qsort() *------------------------------------------------------------ */ int lefLowY(DPOINT *a, DPOINT *b) { DPOINT p = *a; DPOINT q = *b; if (p->y < q->y) return (-1); if (p->y > q->y) return (1); return (0); } /* *------------------------------------------------------------ * lefOrient --- * * Assign a direction to each of the edges in a polygon. * * Note that edges have been sorted, but retain the original * linked list pointers, from which we can determine the * path orientation * *------------------------------------------------------------ */ char lefOrient(DPOINT *edges, int nedges, int *dir) { int n; DPOINT p, q; for (n = 0; n < nedges; n++) { p = edges[n]; q = edges[n]->next; if (p->y == q->y) { dir[n] = HEDGE; continue; } if (p->x == q->x) { if (p->y < q->y) { dir[n] = REDGE; continue; } if (p->y > q->y) { dir[n] = FEDGE; continue; } /* Point connects to itself */ dir[n] = HEDGE; continue; } /* It's not Manhattan, folks. */ return (FALSE); } return (TRUE); } /* *------------------------------------------------------------ * lefCross --- * * See if an edge crosses a particular area. * Return TRUE if edge if vertical and if it crosses the * y-range defined by ybot and ytop. Otherwise return * FALSE. *------------------------------------------------------------ */ char lefCross(DPOINT edge, int dir, double ybot, double ytop) { double ebot, etop; switch (dir) { case REDGE: ebot = edge->y; etop = edge->next->y; return (ebot <= ybot && etop >= ytop); case FEDGE: ebot = edge->next->y; etop = edge->y; return (ebot <= ybot && etop >= ytop); } return (FALSE); } /* *------------------------------------------------------------ * LefPolygonToRects -- * * Convert Geometry information from a POLYGON statement * into rectangles. NOTE: For now, this routine * assumes that all points are Manhattan. It will flag * non-Manhattan geometry * * the DSEG pointed to by rectListPtr is updated by * having the list of rectangles appended to it. * *------------------------------------------------------------ */ void LefPolygonToRects(DSEG *rectListPtr, DPOINT pointlist) { DPOINT ptail, p, *pts, *edges; DSEG rtail, rex, new; int npts = 0; int *dir; int curr, wrapno, n; double xbot, xtop, ybot, ytop; if (pointlist == NULL) return; /* Close the path by duplicating 1st point if necessary */ for (ptail = pointlist; ptail->next; ptail = ptail->next); if ((ptail->x != pointlist->x) || (ptail->y != pointlist->y)) { p = (DPOINT)malloc(sizeof(struct dpoint_)); p->x = pointlist->x; p->y = pointlist->y; p->layer = pointlist->layer; p->next = NULL; ptail->next = p; } // To do: Break out non-manhattan parts here. // See CIFMakeManhattanPath in magic-8.0 rex = NULL; for (p = pointlist; p->next; p = p->next, npts++); pts = (DPOINT *)malloc(npts * sizeof(DPOINT)); edges = (DPOINT *)malloc(npts * sizeof(DPOINT)); dir = (int *)malloc(npts * sizeof(int)); npts = 0; for (p = pointlist; p->next; p = p->next, npts++) { // pts and edges are two lists of pointlist entries // that are NOT linked lists and can be shuffled // around by qsort(). The linked list "next" pointers // *must* be retained. pts[npts] = p; edges[npts] = p; } if (npts < 4) { LefError("Polygon with fewer than 4 points.\n"); goto done; } /* Sort points by low y, edges by low x */ qsort((char *)pts, npts, (int)sizeof(DPOINT), (__compar_fn_t)lefLowY); qsort((char *)edges, npts, (int)sizeof(DPOINT), (__compar_fn_t)lefLowX); /* Find out which direction each edge points */ if (!lefOrient(edges, npts, dir)) { LefError("I can't handle non-manhattan polygons!\n"); goto done; } /* Scan the polygon from bottom to top. At each step, process * a minimum-sized y-range of the polygon (i.e., a range such that * there are no vertices inside the range). Use wrap numbers * based on the edge orientations to determine how much of the * x-range for this y-range should contain material. */ for (curr = 1; curr < npts; curr++) { /* Find the next minimum-sized y-range. */ ybot = pts[curr - 1]->y; while (ybot == pts[curr]->y) if (++curr >= npts) goto done; ytop = pts[curr]->y; /* Process all the edges that cross the y-range, from left * to right. */ for (wrapno = 0, n = 0; n < npts; n++) { if (wrapno == 0) xbot = edges[n]->x; if (!lefCross(edges[n], dir[n], ybot, ytop)) continue; wrapno += (dir[n] == REDGE) ? 1 : -1; if (wrapno == 0) { xtop = edges[n]->x; if (xbot == xtop) continue; new = (DSEG)malloc(sizeof(struct dseg_)); new->x1 = xbot; new->x2 = xtop; new->y1 = ybot; new->y2 = ytop; new->layer = edges[n]->layer; new->next = rex; rex = new; } } } done: free(edges); free(dir); free(pts); if (*rectListPtr == NULL) *rectListPtr = rex; else { for (rtail = *rectListPtr; rtail->next; rtail = rtail->next); rtail->next = rex; } } /* *------------------------------------------------------------ * LefReadPolygon -- * * Read Geometry information from a POLYGON statement * *------------------------------------------------------------ */ DPOINT LefReadPolygon(FILE *f, int curlayer, float oscale) { DPOINT plist = NULL, newPoint; char *token; double px, py; while (1) { token = LefNextToken(f, TRUE); if (token == NULL || *token == ';') break; if (sscanf(token, "%lg", &px) != 1) { LefError("Bad X value in polygon.\n"); LefEndStatement(f); break; } token = LefNextToken(f, TRUE); if (token == NULL || *token == ';') { LefError("Missing Y value in polygon point!\n"); break; } if (sscanf(token, "%lg", &py) != 1) { LefError("Bad Y value in polygon.\n"); LefEndStatement(f); break; } newPoint = (DPOINT)malloc(sizeof(struct dpoint_)); newPoint->x = px / (double)oscale; newPoint->y = py / (double)oscale; newPoint->layer = curlayer; newPoint->next = plist; plist = newPoint; } return plist; } /* *------------------------------------------------------------ * LefReadGeometry -- * * Read Geometry information from a LEF file. * Used for PORT records and OBS statements. * * Results: * Returns a linked list of all areas and types * painted. * * Side Effects: * Reads input from file f; * Paints into the GATE lefMacro. * *------------------------------------------------------------ */ enum lef_geometry_keys {LEF_LAYER = 0, LEF_WIDTH, LEF_PATH, LEF_RECT, LEF_POLYGON, LEF_VIA, LEF_GEOMETRY_END}; DSEG LefReadGeometry(GATE lefMacro, FILE *f, float oscale) { int curlayer = -1, otherlayer = -1; char *token; int keyword; DSEG rectList = (DSEG)NULL; DSEG paintrect, newRect; DPOINT pointlist; static char *geometry_keys[] = { "LAYER", "WIDTH", "PATH", "RECT", "POLYGON", "VIA", "END", NULL }; while ((token = LefNextToken(f, TRUE)) != NULL) { keyword = Lookup(token, geometry_keys); if (keyword < 0) { LefError("Unknown keyword \"%s\" in LEF file; ignoring.\n", token); LefEndStatement(f); continue; } switch (keyword) { case LEF_LAYER: curlayer = LefReadLayers(f, FALSE, &otherlayer); LefEndStatement(f); break; case LEF_WIDTH: LefEndStatement(f); break; case LEF_PATH: LefEndStatement(f); break; case LEF_RECT: paintrect = (curlayer < 0) ? NULL : LefReadRect(f, curlayer, oscale); if (paintrect) { /* Remember the area and layer */ newRect = (DSEG)malloc(sizeof(struct dseg_)); *newRect = *paintrect; newRect->next = rectList; rectList = newRect; } LefEndStatement(f); break; case LEF_POLYGON: pointlist = LefReadPolygon(f, curlayer, oscale); LefPolygonToRects(&rectList, pointlist); break; case LEF_VIA: LefEndStatement(f); break; case LEF_GEOMETRY_END: if (!LefParseEndStatement(f, NULL)) { LefError("Geometry (PORT or OBS) END statement missing.\n"); keyword = -1; } break; } if (keyword == LEF_GEOMETRY_END) break; } return rectList; } /* *------------------------------------------------------------ * LefReadPort -- * * A wrapper for LefReadGeometry, which adds a label * to the last rectangle generated by the geometry * parsing. * * Results: * None. * * Side Effects: * Reads input from file f; * Paints into the GATE lefMacro. * *------------------------------------------------------------ */ void LefReadPort(lefMacro, f, pinName, pinNum, pinDir, pinUse, oscale) GATE lefMacro; FILE *f; char *pinName; int pinNum, pinDir, pinUse; float oscale; { DSEG rectList, rlist; rectList = LefReadGeometry(lefMacro, f, oscale); if (pinName != NULL) lefMacro->node[pinNum] = strdup(pinName); if (pinNum >= 0) { lefMacro->taps[pinNum] = rectList; if (lefMacro->nodes <= pinNum) lefMacro->nodes = (pinNum + 1); } else { while (rectList) { rlist = rectList->next; free(rectList); rectList = rlist; } } } /* *------------------------------------------------------------ * LefReadPin -- * * Read a PIN statement from a LEF file. * * Results: * None. * * Side Effects: * Reads input from file f; * Paints into the GATE lefMacro. * *------------------------------------------------------------ */ enum lef_pin_keys {LEF_DIRECTION = 0, LEF_USE, LEF_PORT, LEF_CAPACITANCE, LEF_PIN_END}; void LefReadPin(lefMacro, f, pinname, pinNum, oscale) GATE lefMacro; FILE *f; char *pinname; int pinNum; float oscale; { char *token; int keyword, subkey; int pinDir = PORT_CLASS_DEFAULT; int pinUse = PORT_USE_DEFAULT; static char *pin_keys[] = { "DIRECTION", "USE", "PORT", "CAPACITANCE", "END", NULL }; static char *pin_classes[] = { "DEFAULT", "INPUT", "OUTPUT TRISTATE", "OUTPUT", "INOUT", "FEEDTHRU", NULL }; static int lef_class_to_bitmask[] = { PORT_CLASS_DEFAULT, PORT_CLASS_INPUT, PORT_CLASS_TRISTATE, PORT_CLASS_OUTPUT, PORT_CLASS_BIDIRECTIONAL, PORT_CLASS_FEEDTHROUGH }; static char *pin_uses[] = { "DEFAULT", "SIGNAL", "ANALOG", "POWER", "GROUND", "CLOCK", NULL }; static int lef_use_to_bitmask[] = { PORT_USE_DEFAULT, PORT_USE_SIGNAL, PORT_USE_ANALOG, PORT_USE_POWER, PORT_USE_GROUND, PORT_USE_CLOCK }; while ((token = LefNextToken(f, TRUE)) != NULL) { keyword = Lookup(token, pin_keys); if (keyword < 0) { LefError("Unknown keyword \"%s\" in LEF file; ignoring.\n", token); LefEndStatement(f); continue; } switch (keyword) { case LEF_DIRECTION: token = LefNextToken(f, TRUE); subkey = Lookup(token, pin_classes); if (subkey < 0) LefError("Improper DIRECTION statement\n"); else pinDir = lef_class_to_bitmask[subkey]; LefEndStatement(f); break; case LEF_USE: token = LefNextToken(f, TRUE); subkey = Lookup(token, pin_uses); if (subkey < 0) LefError("Improper USE statement\n"); else pinUse = lef_use_to_bitmask[subkey]; LefEndStatement(f); break; case LEF_PORT: LefReadPort(lefMacro, f, pinname, pinNum, pinDir, pinUse, oscale); break; case LEF_CAPACITANCE: LefEndStatement(f); /* Ignore. . . */ break; case LEF_PIN_END: if (!LefParseEndStatement(f, pinname)) { LefError("Pin END statement missing.\n"); keyword = -1; } break; } if (keyword == LEF_PIN_END) break; } } /* *------------------------------------------------------------ * LefEndStatement -- * * Read file input to EOF or a ';' token (end-of-statement) * If we encounter a quote, make sure we don't terminate * the statement on a semicolon that is part of the * quoted material. * *------------------------------------------------------------ */ void LefEndStatement(FILE *f) { char *token; while ((token = LefNextToken(f, TRUE)) != NULL) if (*token == ';') break; } /* *------------------------------------------------------------ * * LefReadMacro -- * * Read in a MACRO section from a LEF file. * * Results: * None. * * Side Effects: * Creates a new cell definition in the database. * *------------------------------------------------------------ */ enum lef_macro_keys {LEF_CLASS = 0, LEF_SIZE, LEF_ORIGIN, LEF_SYMMETRY, LEF_SOURCE, LEF_SITE, LEF_PIN, LEF_OBS, LEF_TIMING, LEF_FOREIGN, LEF_MACRO_END}; void LefReadMacro(f, mname, oscale) FILE *f; /* LEF file being read */ char *mname; /* name of the macro */ float oscale; /* scale factor to um, usually 1 */ { GATE lefMacro, altMacro; char *token, tsave[128]; int keyword, pinNum; float x, y; u_char has_size, is_imported = FALSE; struct dseg_ lefBBox; static char *macro_keys[] = { "CLASS", "SIZE", "ORIGIN", "SYMMETRY", "SOURCE", "SITE", "PIN", "OBS", "TIMING", "FOREIGN", "END", NULL }; /* Start by creating a new celldef */ lefMacro = (GATE)NULL; for (altMacro = GateInfo; altMacro; altMacro = altMacro->next) { if (!strcmp(altMacro->gatename, mname)) { lefMacro = altMacro; break; } } while (lefMacro) { int suffix; char newname[256]; altMacro = lefMacro; for (suffix = 1; altMacro != NULL; suffix++) { sprintf(newname, "%250s_%d", mname, suffix); for (altMacro = GateInfo; altMacro; altMacro = altMacro->next) if (!strcmp(altMacro->gatename, newname)) break; } LefError("Cell \"%s\" was already defined in this file. " "Renaming original cell \"%s\"\n", mname, newname); lefMacro->gatename = strdup(newname); lefMacro = lefFindCell(mname); } // Create the new cell lefMacro = (GATE)malloc(sizeof(struct gate_)); lefMacro->gatename = strdup(mname); lefMacro->gatetype = NULL; lefMacro->width = 0.0; lefMacro->height = 0.0; lefMacro->placedX = 0.0; lefMacro->placedY = 0.0; lefMacro->obs = (DSEG)NULL; lefMacro->next = GateInfo; lefMacro->nodes = 0; GateInfo = lefMacro; /* Initial values */ pinNum = 0; has_size = FALSE; lefBBox.x1 = 0.0; lefBBox.y1 = 0.0; while ((token = LefNextToken(f, TRUE)) != NULL) { keyword = Lookup(token, macro_keys); if (keyword < 0) { LefError("Unknown keyword \"%s\" in LEF file; ignoring.\n", token); LefEndStatement(f); continue; } switch (keyword) { case LEF_CLASS: token = LefNextToken(f, TRUE); if (*token != '\n') // DBPropPut(lefMacro, "LEFclass", token); ; LefEndStatement(f); break; case LEF_SIZE: token = LefNextToken(f, TRUE); if (!token || sscanf(token, "%f", &x) != 1) goto size_error; token = LefNextToken(f, TRUE); /* skip keyword "BY" */ if (!token) goto size_error; token = LefNextToken(f, TRUE); if (!token || sscanf(token, "%f", &y) != 1) goto size_error; lefBBox.x2 = x + lefBBox.x1; lefBBox.y2 = y + lefBBox.y1; has_size = TRUE; LefEndStatement(f); break; size_error: LefError("Bad macro SIZE; requires values X BY Y.\n"); LefEndStatement(f); break; case LEF_ORIGIN: token = LefNextToken(f, TRUE); if (!token || sscanf(token, "%f", &x) != 1) goto origin_error; token = LefNextToken(f, TRUE); if (!token || sscanf(token, "%f", &y) != 1) goto origin_error; lefBBox.x1 = -x; lefBBox.y1 = -y; if (has_size) { lefBBox.x2 += lefBBox.x1; lefBBox.y2 += lefBBox.y1; } LefEndStatement(f); break; origin_error: LefError("Bad macro ORIGIN; requires 2 values.\n"); LefEndStatement(f); break; case LEF_SYMMETRY: token = LefNextToken(f, TRUE); if (*token != '\n') // DBPropPut(lefMacro, "LEFsymmetry", token + strlen(token) + 1); ; LefEndStatement(f); break; case LEF_SOURCE: token = LefNextToken(f, TRUE); if (*token != '\n') // DBPropPut(lefMacro, "LEFsource", token); ; LefEndStatement(f); break; case LEF_SITE: token = LefNextToken(f, TRUE); if (*token != '\n') // DBPropPut(lefMacro, "LEFsite", token); ; LefEndStatement(f); break; case LEF_PIN: token = LefNextToken(f, TRUE); /* Diagnostic */ /* Fprintf(stdout, " Macro defines pin %s\n", token); */ sprintf(tsave, "%.127s", token); if (is_imported) LefSkipSection(f, tsave); else LefReadPin(lefMacro, f, tsave, pinNum++, oscale); break; case LEF_OBS: /* Diagnostic */ /* Fprintf(stdout, " Macro defines obstruction\n"); */ if (is_imported) LefSkipSection(f, NULL); else lefMacro->obs = LefReadGeometry(lefMacro, f, oscale); break; case LEF_TIMING: LefSkipSection(f, macro_keys[LEF_TIMING]); break; case LEF_FOREIGN: LefEndStatement(f); break; case LEF_MACRO_END: if (!LefParseEndStatement(f, mname)) { LefError("Macro END statement missing.\n"); keyword = -1; } break; } if (keyword == LEF_MACRO_END) break; } /* Finish up creating the cell */ if (lefMacro) { if (has_size) { lefMacro->width = (lefBBox.x2 - lefBBox.x1); lefMacro->height = (lefBBox.y2 - lefBBox.y1); /* "placed" for macros (not instances) corresponds to the */ /* cell origin. */ lefMacro->placedX = lefBBox.x1; lefMacro->placedY = lefBBox.y1; } else { LefError("Gate %s has no size information!\n", lefMacro->gatename); } } } /* *------------------------------------------------------------ * * LefAddViaGeometry -- * * Read in geometry for a VIA section from a LEF or DEF * file. * * f LEF file being read * lefl pointer to via info * curlayer current tile type * oscale output scaling * * Results: * None. * * Side Effects: * Adds to the lefLayer record for a via definition. * *------------------------------------------------------------ */ void LefAddViaGeometry(FILE *f, LefList lefl, int curlayer, float oscale) { DSEG currect; DSEG viarect; /* Rectangles for vias are read in units of 1/2 lambda */ currect = LefReadRect(f, curlayer, (oscale / 2)); if (currect == NULL) return; /* First rect goes into info.via.area, others go into info.via.lr */ if (lefl->info.via.area.layer < 0) { lefl->info.via.area = *currect; } else { viarect = (DSEG)malloc(sizeof(struct dseg_)); *viarect = *currect; viarect->next = lefl->info.via.lr; lefl->info.via.lr = viarect; } } /* *------------------------------------------------------------ * * LefReadLayerSection -- * * Read in a LAYER, VIA, or VIARULE section from a LEF file. * * Results: * None. * * Side Effects: * Adds to the LEF layer info hash table. * *------------------------------------------------------------ */ enum lef_layer_keys {LEF_LAYER_TYPE=0, LEF_LAYER_WIDTH, LEF_LAYER_SPACING, LEF_LAYER_SPACINGTABLE, LEF_LAYER_PITCH, LEF_LAYER_DIRECTION, LEF_LAYER_OFFSET, LEF_VIA_DEFAULT, LEF_VIA_LAYER, LEF_VIA_RECT, LEF_VIARULE_VIA, LEF_LAYER_END}; enum lef_spacing_keys {LEF_SPACING_RANGE=0, LEF_END_LAYER_SPACING}; void LefReadLayerSection(f, lname, mode, lefl) FILE *f; /* LEF file being read */ char *lname; /* name of the layer */ int mode; /* layer, via, or viarule */ LefList lefl; /* pointer to layer info */ { char *token, *tp; int keyword, typekey, entries, i; struct seg_ viaArea; int curlayer = -1; double dvalue, oscale; lefSpacingRule *newrule, *testrule; /* These are defined in the order of CLASS_* in lefInt.h */ static char *layer_type_keys[] = { "ROUTING", "CUT", "MASTERSLICE", "OVERLAP", NULL }; static char *layer_keys[] = { "TYPE", "WIDTH", "SPACING", "SPACINGTABLE", "PITCH", "DIRECTION", "OFFSET", "DEFAULT", "LAYER", "RECT", "VIA", "END", NULL }; static char *spacing_keys[] = { "RANGE", ";", NULL }; /* Database is assumed to be in microns. */ /* If not, we need to parse the UNITS record, which is */ /* currently ignored. */ oscale = 1; viaArea.x1 = viaArea.x2 = 0; viaArea.y1 = viaArea.y2 = 0; viaArea.layer = -1; while ((token = LefNextToken(f, TRUE)) != NULL) { keyword = Lookup(token, layer_keys); if (keyword < 0) { LefError("Unknown keyword \"%s\" in LEF file; ignoring.\n", token); LefEndStatement(f); continue; } switch (keyword) { case LEF_LAYER_TYPE: token = LefNextToken(f, TRUE); if (*token != '\n') { typekey = Lookup(token, layer_type_keys); if (typekey < 0) LefError("Unknown layer type \"%s\" in LEF file; " "ignoring.\n", token); } if (lefl->lefClass == CLASS_IGNORE) { lefl->lefClass = typekey; if (typekey == CLASS_ROUTE) { lefl->info.route.width = 0.0; lefl->info.route.spacing = NULL; lefl->info.route.pitch = 0.0; // Use -1.0 as an indication that offset has not // been specified and needs to be set to default. lefl->info.route.offset = -1.0; lefl->info.route.hdirection = (u_char)0; /* A routing type has been declared. Assume */ /* this takes the name "metal1", "M1", or some */ /* variant thereof. */ for (tp = lefl->lefName; *tp != '\0'; tp++) { if (*tp >= '0' && *tp <= '9') { sscanf(tp, "%d", &lefl->type); /* "metal1", e.g., is assumed to be layer #0 */ /* This may not be a proper assumption, always */ lefl->type--; break; } } /* This is probably some special non-numerical */ /* name for a top metal layer. Take a stab at */ /* it, defining it to be the next layer up from */ /* whatever the previous topmost route layer */ /* was. This should work unless the LEF file */ /* is really weirdly written. */ if (lefl->type < 0) { lefl->type = LefGetMaxLayer(); } } else if (typekey == CLASS_VIA) { lefl->info.via.area.x1 = 0.0; lefl->info.via.area.y1 = 0.0; lefl->info.via.area.x2 = 0.0; lefl->info.via.area.y2 = 0.0; lefl->info.via.area.layer = -1; lefl->info.via.cell = (GATE)NULL; lefl->info.via.lr = (DSEG)NULL; } } else if (lefl->lefClass != typekey) { LefError("Attempt to reclassify layer %s from %s to %s\n", lname, layer_type_keys[lefl->lefClass], layer_type_keys[typekey]); } LefEndStatement(f); break; case LEF_LAYER_WIDTH: token = LefNextToken(f, TRUE); sscanf(token, "%lg", &dvalue); lefl->info.route.width = dvalue / (double)oscale; LefEndStatement(f); break; case LEF_LAYER_SPACING: token = LefNextToken(f, TRUE); sscanf(token, "%lg", &dvalue); token = LefNextToken(f, TRUE); typekey = Lookup(token, spacing_keys); newrule = (lefSpacingRule *)malloc(sizeof(lefSpacingRule)); // If no range specified, then the rule goes in front if (typekey != LEF_SPACING_RANGE) { newrule->spacing = dvalue / (double)oscale; newrule->width = 0.0; newrule->next = lefl->info.route.spacing; lefl->info.route.spacing = newrule; } else { // Get range minimum, ignore range maximum, and sort // the spacing order. newrule->spacing = dvalue / (double)oscale; token = LefNextToken(f, TRUE); sscanf(token, "%lg", &dvalue); newrule->width = dvalue / (double)oscale; for (testrule = lefl->info.route.spacing; testrule; testrule = testrule->next) if (testrule->next == NULL || testrule->next->width > newrule->width) break; if (!testrule) { newrule->next = NULL; lefl->info.route.spacing = newrule; } else { newrule->next = testrule->next; testrule->next = newrule; } token = LefNextToken(f, TRUE); typekey = Lookup(token, spacing_keys); } if (typekey != LEF_END_LAYER_SPACING) LefEndStatement(f); break; case LEF_LAYER_SPACINGTABLE: // Use the values for the maximum parallel runlength token = LefNextToken(f, TRUE); // "PARALLELRUNLENTTH" entries = 0; while (1) { token = LefNextToken(f, TRUE); if (*token == ';' || !strcmp(token, "WIDTH")) break; else entries++; } if (*token != ';') newrule = (lefSpacingRule *)malloc(sizeof(lefSpacingRule)); while (*token != ';') { token = LefNextToken(f, TRUE); // Minimum width value sscanf(token, "%lg", &dvalue); newrule->width = dvalue / (double)oscale; for (i = 0; i < entries; i++) { token = LefNextToken(f, TRUE); // Spacing value } sscanf(token, "%lg", &dvalue); newrule->spacing = dvalue / (double)oscale; token = LefNextToken(f, TRUE); for (testrule = lefl->info.route.spacing; testrule; testrule = testrule->next) if (testrule->next == NULL || testrule->next->width > newrule->width) break; if (!testrule) { newrule->next = NULL; lefl->info.route.spacing = newrule; } else { newrule->next = testrule->next; testrule->next = newrule; } token = LefNextToken(f, TRUE); if (strcmp(token, "WIDTH")) break; } break; case LEF_LAYER_PITCH: token = LefNextToken(f, TRUE); sscanf(token, "%lg", &dvalue); lefl->info.route.pitch = dvalue / (double)oscale; /* Offset default is 1/2 the pitch. Offset is */ /* intialized to -1 to tell whether or not the value */ /* has been set by an OFFSET statement. */ if (lefl->info.route.offset < 0.0) lefl->info.route.offset = lefl->info.route.pitch / 2.0; LefEndStatement(f); break; case LEF_LAYER_DIRECTION: token = LefNextToken(f, TRUE); LefLower(token); lefl->info.route.hdirection = (token[0] == 'h') ? TRUE : FALSE; LefEndStatement(f); break; case LEF_LAYER_OFFSET: token = LefNextToken(f, TRUE); sscanf(token, "%lg", &dvalue); lefl->info.route.offset = dvalue / (double)oscale; LefEndStatement(f); break; case LEF_VIA_DEFAULT: /* Do nothing; especially, don't look for end-of-statement! */ break; case LEF_VIA_LAYER: curlayer = LefReadLayer(f, FALSE); LefEndStatement(f); break; case LEF_VIA_RECT: LefAddViaGeometry(f, lefl, curlayer, oscale); LefEndStatement(f); break; case LEF_VIARULE_VIA: LefEndStatement(f); break; case LEF_LAYER_END: if (!LefParseEndStatement(f, lname)) { LefError("Layer END statement missing.\n"); keyword = -1; } break; } if (keyword == LEF_LAYER_END) break; } } /* *------------------------------------------------------------ * * LefRead -- * * Read a .lef file and generate all routing configuration * structures and values from the LAYER, VIA, and MACRO sections * * Results: * None. * * Side Effects: * Many. Cell definitions are created and added to * the GateInfo database. * *------------------------------------------------------------ */ enum lef_sections {LEF_VERSION = 0, LEF_NAMESCASESENSITIVE, LEF_PROPERTYDEFS, LEF_UNITS, LEF_SECTION_LAYER, LEF_SECTION_VIA, LEF_SECTION_VIARULE, LEF_SECTION_SPACING, LEF_SECTION_SITE, LEF_PROPERTY, LEF_NOISETABLE, LEF_CORRECTIONTABLE, LEF_IRDROP, LEF_ARRAY, LEF_SECTION_TIMING, LEF_EXTENSION, LEF_MACRO, LEF_END}; void LefRead(inName) char *inName; { FILE *f; char filename[256]; char *token; char tsave[128]; int keyword, layer; float oscale; double xydiff; LefList lefl; DSEG grect; GATE gateginfo; static char *sections[] = { "VERSION", "NAMESCASESENSITIVE", "PROPERTYDEFINITIONS", "UNITS", "LAYER", "VIA", "VIARULE", "SPACING", "SITE", "PROPERTY", "NOISETABLE", "CORRECTIONTABLE", "IRDROP", "ARRAY", "TIMING", "BEGINEXT", "MACRO", "END", NULL }; if (!strrchr(inName, '.')) sprintf(filename, "%s.lef", inName); else strcpy(filename, inName); f = fopen(filename, "r"); if (f == NULL) { Fprintf(stderr, "Cannot open input file: "); perror(filename); return; } if (Verbose > 0) { Fprintf(stdout, "Reading LEF data from file %s.\n", filename); Flush(stdout); } oscale = 1; while ((token = LefNextToken(f, TRUE)) != NULL) { keyword = Lookup(token, sections); if (keyword < 0) { LefError("Unknown keyword \"%s\" in LEF file; ignoring.\n", token); LefEndStatement(f); continue; } switch (keyword) { case LEF_VERSION: LefEndStatement(f); break; case LEF_NAMESCASESENSITIVE: LefEndStatement(f); break; case LEF_PROPERTYDEFS: LefSkipSection(f, sections[LEF_PROPERTYDEFS]); break; case LEF_UNITS: LefSkipSection(f, sections[LEF_UNITS]); break; case LEF_SECTION_VIA: case LEF_SECTION_VIARULE: token = LefNextToken(f, TRUE); sprintf(tsave, "%.127s", token); lefl = LefFindLayer(token); if (lefl == NULL) { lefl = (LefList)calloc(1, sizeof(lefLayer)); lefl->type = -1; lefl->obsType = -1; lefl->lefClass = CLASS_VIA; lefl->info.via.area.x1 = 0.0; lefl->info.via.area.y1 = 0.0; lefl->info.via.area.x2 = 0.0; lefl->info.via.area.y2 = 0.0; lefl->info.via.area.layer = -1; lefl->info.via.cell = (GATE)NULL; lefl->info.via.lr = (DSEG)NULL; lefl->lefName = strdup(token); lefl->next = LefInfo; LefInfo = lefl; LefReadLayerSection(f, tsave, keyword, lefl); } else if (keyword == LEF_SECTION_VIARULE) /* If we've already seen this via, don't reprocess. */ /* This deals with VIA followed by VIARULE. We */ /* really ought to have special processing for the */ /* VIARULE section. . . */ LefSkipSection(f, tsave); else { LefError("Warning: Cut type \"%s\" redefined.\n", token); lefl = LefRedefined(lefl, token); LefReadLayerSection(f, tsave, keyword, lefl); } break; case LEF_SECTION_LAYER: token = LefNextToken(f, TRUE); sprintf(tsave, "%.127s", token); lefl = LefFindLayer(token); if (lefl == (LefList)NULL) { lefl = (LefList)malloc(sizeof(lefLayer)); lefl->type = -1; lefl->obsType = -1; lefl->lefClass = CLASS_IGNORE; /* For starters */ lefl->lefName = strdup(token); lefl->next = LefInfo; LefInfo = lefl; } else { if (lefl && lefl->type < 0) { LefError("Layer %s is only defined for obstructions!\n", token); LefSkipSection(f, tsave); break; } } LefReadLayerSection(f, tsave, keyword, lefl); break; case LEF_SECTION_SPACING: LefSkipSection(f, sections[LEF_SECTION_SPACING]); break; case LEF_SECTION_SITE: token = LefNextToken(f, TRUE); if (Verbose > 0) Fprintf(stdout, "LEF file: Defines site %s (ignored)\n", token); sprintf(tsave, "%.127s", token); LefSkipSection(f, tsave); break; case LEF_PROPERTY: LefSkipSection(f, NULL); break; case LEF_NOISETABLE: LefSkipSection(f, sections[LEF_NOISETABLE]); break; case LEF_CORRECTIONTABLE: LefSkipSection(f, sections[LEF_CORRECTIONTABLE]); break; case LEF_IRDROP: LefSkipSection(f, sections[LEF_IRDROP]); break; case LEF_ARRAY: LefSkipSection(f, sections[LEF_ARRAY]); break; case LEF_SECTION_TIMING: LefSkipSection(f, sections[LEF_SECTION_TIMING]); break; case LEF_EXTENSION: LefSkipSection(f, sections[LEF_EXTENSION]); break; case LEF_MACRO: token = LefNextToken(f, TRUE); /* Diagnostic */ /* Fprintf(stdout, "LEF file: Defines new cell %s\n", token); */ sprintf(tsave, "%.127s", token); LefReadMacro(f, tsave, oscale); break; case LEF_END: if (!LefParseEndStatement(f, "LIBRARY")) { LefError("END statement out of context.\n"); keyword = -1; } break; } if (keyword == LEF_END) break; } if (Verbose > 0) { Fprintf(stdout, "LEF read: Processed %d lines.\n", lefCurrentLine); LefError(NULL); /* print statement of errors, if any */ } /* Cleanup */ if (f != NULL) fclose(f); /* Make sure that the gate list has one entry called "pin" */ for (gateginfo = GateInfo; gateginfo; gateginfo = gateginfo->next) if (!strcasecmp(gateginfo->gatename, "pin")) break; if (!gateginfo) { /* Add a new GateInfo entry for pseudo-gate "pin" */ gateginfo = (GATE)malloc(sizeof(struct gate_)); gateginfo->gatetype = NULL; gateginfo->gatename = (char *)malloc(4); strcpy(gateginfo->gatename, "pin"); gateginfo->node[0] = strdup("pin"); gateginfo->width = 0.0; gateginfo->height = 0.0; gateginfo->placedX = 0.0; gateginfo->placedY = 0.0; gateginfo->nodes = 1; grect = (DSEG)malloc(sizeof(struct dseg_)); grect->x1 = grect->x2 = 0.0; grect->y1 = grect->y2 = 0.0; grect->next = (DSEG)NULL; gateginfo->taps[0] = grect; gateginfo->obs = (DSEG)NULL; gateginfo->next = GateInfo; GateInfo = gateginfo; } PinMacro = gateginfo; /* Work through all of the defined layers, and copy the names into */ /* the strings used for route output, overriding any information */ /* that may have been in the route.cfg file. */ /* Note that this runs through all the defined vias, from last to */ /* first defined. Check the X vs. Y dimension of the base layer. */ /* If X is longer, save as ViaX. If Y is longer, save as ViaY. */ for (lefl = LefInfo; lefl; lefl = lefl->next) { if (lefl->lefClass == CLASS_ROUTE) { strcpy(CIFLayer[lefl->type], lefl->lefName); } else if (lefl->lefClass == CLASS_VIA) { if (lefl->info.via.lr) { layer = MAX_LAYERS; if (lefl->info.via.area.layer >= 0) { layer = lefl->info.via.area.layer; xydiff = (lefl->info.via.area.x2 - lefl->info.via.area.x1) - (lefl->info.via.area.y2 - lefl->info.via.area.y1); } for (grect = lefl->info.via.lr; grect; grect = grect->next) { if (grect->layer >= 0 && grect->layer < layer) { layer = grect->layer; xydiff = (grect->x2 - grect->x1) - (grect->y2 - grect->y1); } } if (layer < MAX_LAYERS) { if (xydiff > -EPS) { free(ViaX[layer]); ViaX[layer] = strdup(lefl->lefName); } else { if (ViaY[layer] != NULL) free(ViaY[layer]); ViaY[layer] = strdup(lefl->lefName); } } } } } } qrouter-1.3.33/.gitignore0000664000175000001440000000017012406043506014002 0ustar timusersqrouter config.cache config.status config.log Makefile qrouterexec qrouter.sh qrouter.tcl *.o *.so *~ UPDATE_ME VERSION qrouter-1.3.33/def.c0000644000175000001440000013532212406043443012722 0ustar timusers/* * def.c -- * * This module incorporates the LEF/DEF format for standard-cell place and * route. * * Version 0.1 (September 26, 2003): DEF input of designs. * * Written by Tim Edwards, Open Circuit Design * Modified April 2013 for use with qrouter * * It is assumed that the LEF files have been read in prior to this, and * layer information is already known. The DEF file should have information * primarily on die are, track placement, pins, components, and nets. * * To-do: Routed nets should have their routes dropped into track obstructions, * and the nets should be ignored. Currently, routed nets are parsed and the * routes are ignored. */ #include #include #include #include #include #include #include /* for roundf() function, if std=c99 */ #include "qrouter.h" #include "node.h" #include "qconfig.h" #include "maze.h" #include "lef.h" #ifndef TCL_QROUTER /* Find an instance in the instance list. If qrouter */ /* is compiled with Tcl support, then this routine is */ /* found in tclqrouter.c and uses hash tables, greatly */ /* speeding up the read-in of large DEF files. */ GATE DefFindInstance(char *name) { GATE ginst; for (ginst = Nlgates; ginst; ginst = ginst->next) { if (!strcasecmp(ginst->gatename, name)) return ginst; } return NULL; } /* For the non-Tcl version, this is an empty placeholder */ void DefHashInstance(GATE gateginfo) { } #endif /* TCL_QROUTER */ /* *------------------------------------------------------------ * * DefAddRoutes -- * * Parse a network route statement from the DEF file. * If "special" is 1, then, add the geometry to the * list of obstructions. If "special" is 0, then read * the geometry into a route structure for the net. * * Results: * Returns the last token encountered. * * Side Effects: * Reads from input stream; * Adds information to the layout database. * *------------------------------------------------------------ */ char * DefAddRoutes(FILE *f, float oscale, NET net, char special) { char *token; SEG newRoute = NULL; DSEG lr, drect; struct point_ refp; char valid = FALSE; /* is there a valid reference point? */ char initial = TRUE; struct dseg_ locarea; double x, y, lx, ly, w; int routeLayer, paintLayer; LefList lefl; NODE node; ROUTE routednet = NULL; node = net->netnodes; /* Set pitches and allocate memory for Obs[] if we haven't yet. */ set_num_channels(); while (initial || (token = LefNextToken(f, TRUE)) != NULL) { /* Get next point, token "NEW", or via name */ if (initial || !strcmp(token, "NEW") || !strcmp(token, "new")) { /* initial pass is like a NEW record, but has no NEW keyword */ initial = FALSE; /* invalidate reference point */ valid = FALSE; token = LefNextToken(f, TRUE); routeLayer = LefFindLayerNum(token); if (routeLayer < 0) { LefError("Unknown layer type \"%s\" for NEW route\n", token); continue; } paintLayer = routeLayer; if (special) { /* SPECIALNETS has the additional width */ token = LefNextToken(f, TRUE); if (sscanf(token, "%lg", &w) != 1) { LefError("Bad width in special net\n"); continue; } if (w != 0) w /= oscale; else w = LefGetRouteWidth(paintLayer); } else w = LefGetRouteWidth(paintLayer); // Create a new route record, add to the 1st node if (special == (char)0) { routednet = (ROUTE)malloc(sizeof(struct route_)); routednet->next = net->routes; net->routes = routednet; routednet->netnum = net->netnum; routednet->segments = NULL; routednet->flags = (u_char)0; } } else if (*token != '(') /* via name */ { /* A '+' or ';' record ends the route */ if (*token == ';' || *token == '+') break; else if (valid == FALSE) { LefError("Route has via name \"%s\" but no points!\n", token); continue; } lefl = LefFindLayer(token); if (lefl != NULL) { /* The area to paint is derived from the via definitions. */ if (lefl != NULL) { if (lefl->lefClass == CLASS_VIA) { paintLayer = Num_layers - 1; routeLayer = -1; lr = lefl->info.via.lr; while (lr != NULL) { routeLayer = lr->layer; if (routeLayer < paintLayer) paintLayer = routeLayer; if ((routeLayer >= 0) && (special == (char)1) && (valid == TRUE)) { drect = (DSEG)malloc(sizeof(struct dseg_)); drect->x1 = x + lr->x1; drect->x2 = x + lr->x2; drect->y1 = y + lr->y1; drect->y2 = y + lr->y2; drect->layer = lr->layer; drect->next = UserObs; UserObs = drect; } lr = lr->next; } if (routeLayer == -1) paintLayer = lefl->type; } else paintLayer = lefl->type; } else { LefError("Error: Via \"%s\" named but undefined.\n", token); paintLayer = routeLayer; } if ((special == (char)0) && (paintLayer >= 0)) { newRoute = (SEG)malloc(sizeof(struct seg_)); newRoute->segtype = ST_VIA; newRoute->x1 = refp.x1; newRoute->x2 = refp.x1; newRoute->y1 = refp.y1; newRoute->y2 = refp.y1; newRoute->layer = paintLayer; if (routednet == NULL) { routednet = (ROUTE)malloc(sizeof(struct route_)); routednet->next = net->routes; net->routes = routednet; routednet->netnum = net->netnum; routednet->segments = NULL; routednet->flags = (u_char)0; } newRoute->next = routednet->segments; routednet->segments = newRoute; } else LefError("Via \"%s\" does not define a metal layer!\n", token); } else LefError("Via name \"%s\" unknown in route.\n", token); } else { /* Revert to the routing layer type, in case we painted a via */ paintLayer = routeLayer; /* Record current reference point */ locarea.x1 = refp.x1; locarea.y1 = refp.y1; lx = x; ly = y; /* Read an (X Y) point */ token = LefNextToken(f, TRUE); /* read X */ if (*token == '*') { if (valid == FALSE) { LefError("No reference point for \"*\" wildcard\n"); goto endCoord; } } else if (sscanf(token, "%lg", &x) == 1) { x /= oscale; // In microns refp.x1 = (int)((x - Xlowerbound + EPS) / PitchX[paintLayer]); } else { LefError("Cannot parse X coordinate.\n"); goto endCoord; } token = LefNextToken(f, TRUE); /* read Y */ if (*token == '*') { if (valid == FALSE) { LefError("No reference point for \"*\" wildcard\n"); if (newRoute != NULL) { free(newRoute); newRoute = NULL; } goto endCoord; } } else if (sscanf(token, "%lg", &y) == 1) { y /= oscale; // In microns refp.y1 = (int)((y - Ylowerbound + EPS) / PitchY[paintLayer]); } else { LefError("Cannot parse Y coordinate.\n"); goto endCoord; } /* Indicate that we have a valid reference point */ if (valid == FALSE) { valid = TRUE; } else if ((locarea.x1 != refp.x1) && (locarea.y1 != refp.y1)) { /* Skip over nonmanhattan segments, reset the reference */ /* point, and output a warning. */ LefError("Can't deal with nonmanhattan geometry in route.\n"); locarea.x1 = refp.x1; locarea.y1 = refp.y1; lx = x; ly = y; } else { locarea.x2 = refp.x1; locarea.y2 = refp.y1; lx = x; ly = y; if (special == (char)1) { if (valid == TRUE) { drect = (DSEG)malloc(sizeof(struct dseg_)); if (lx > x) { drect->x1 = x - w; drect->x2 = lx + w; } else { drect->x1 = x + w; drect->x2 = lx - w; } if (ly > y) { drect->y1 = y - w; drect->y2 = ly + w; } else { drect->y1 = y + w; drect->y2 = ly - w; } drect->layer = routeLayer; drect->next = UserObs; UserObs = drect; } } else if (paintLayer >= 0) { newRoute = (SEG)malloc(sizeof(struct seg_)); newRoute->segtype = ST_WIRE; newRoute->x1 = locarea.x1; newRoute->x2 = locarea.x2; newRoute->y1 = locarea.y1; newRoute->y2 = locarea.y2; newRoute->layer = paintLayer; if (routednet == NULL) { routednet = (ROUTE)malloc(sizeof(struct route_)); routednet->next = net->routes; net->routes = routednet; routednet->netnum = net->netnum; routednet->segments = NULL; routednet->flags = (u_char)0; } newRoute->next = routednet->segments; routednet->segments = newRoute; } } endCoord: /* Find the closing parenthesis for the coordinate pair */ while (*token != ')') token = LefNextToken(f, TRUE); } } /* Make sure we have allocated memory for nets */ allocate_obs_array(); /* Write the route(s) back into Obs[] */ writeback_all_routes(net); return token; /* Pass back the last token found */ } /* *------------------------------------------------------------ * * DefReadGatePin --- * * Given a gate name and a pin name in a net from the * DEF file NETS section, find the position of the * gate, then the position of the pin within the gate, * and add pin and obstruction information to the grid * network. * *------------------------------------------------------------ */ void DefReadGatePin(NET net, NODE node, char *instname, char *pinname, double *home) { NODE node2; int i, j; GATE gateginfo; DSEG drect; GATE g; double dx, dy; int gridx, gridy; DPOINT dp; g = DefFindInstance(instname); if (g) { gateginfo = g->gatetype; if (!gateginfo) { LefError("Endpoint %s/%s of net %s not found\n", instname, pinname, net->netname); return; } for (i = 0; i < gateginfo->nodes; i++) { if (!strcasecmp(gateginfo->node[i], pinname)) { node->taps = (DPOINT)NULL; node->extend = (DPOINT)NULL; for (drect = g->taps[i]; drect; drect = drect->next) { // Add all routing gridpoints that fall inside // the rectangle. Much to do here: // (1) routable area should extend 1/2 route width // to each side, as spacing to obstructions allows. // (2) terminals that are wide enough to route to // but not centered on gridpoints should be marked // in some way, and handled appropriately. gridx = (int)((drect->x1 - Xlowerbound) / PitchX[drect->layer]) - 1; if (gridx < 0) gridx = 0; while (1) { dx = (gridx * PitchX[drect->layer]) + Xlowerbound; if (dx > drect->x2 + home[drect->layer]) break; if (dx < drect->x1 - home[drect->layer]) { gridx++; continue; } gridy = (int)((drect->y1 - Ylowerbound) / PitchY[drect->layer]) - 1; if (gridy < 0) gridy = 0; while (1) { dy = (gridy * PitchY[drect->layer]) + Ylowerbound; if (dy > drect->y2 + home[drect->layer]) break; if (dy < drect->y1 - home[drect->layer]) { gridy++; continue; } // Routing grid point is an interior point // of a gate port. Record the position dp = (DPOINT)malloc(sizeof(struct dpoint_)); dp->layer = drect->layer; dp->x = dx; dp->y = dy; dp->gridx = gridx; dp->gridy = gridy; if (dy >= drect->y1 && dx >= drect->x1 && dy <= drect->y2 && dx <= drect->x2) { dp->next = node->taps; node->taps = dp; } else { dp->next = node->extend; node->extend = dp; } gridy++; } gridx++; } } node->netnum = net->netnum; g->netnum[i] = net->netnum; g->noderec[i] = node; node->netname = net->netname; node->next = net->netnodes; net->netnodes = node; break; } } if (i < gateginfo->nodes) return; } } /* *------------------------------------------------------------ * * DefReadNets -- * * Read a NETS or SPECIALNETS section from a DEF file. * * Results: * None. * * Side Effects: * Many. Networks are created, and geometry may be * painted into the database top-level cell. * *------------------------------------------------------------ */ enum def_net_keys {DEF_NET_START = 0, DEF_NET_END}; enum def_netprop_keys { DEF_NETPROP_USE = 0, DEF_NETPROP_ROUTED, DEF_NETPROP_FIXED, DEF_NETPROP_COVER, DEF_NETPROP_SHAPE, DEF_NETPROP_SOURCE, DEF_NETPROP_WEIGHT, DEF_NETPROP_PROPERTY}; void DefReadNets(FILE *f, char *sname, float oscale, char special, int total) { char *token; int keyword, subkey; int i, processed = 0; int nodeidx; char instname[MAX_NAME_LEN], pinname[MAX_NAME_LEN]; NET net; int netidx; NODE node, node2; GATE gateginfo; DSEG drect; GATE g; double dx, dy; int gridx, gridy; DPOINT dp; double home[MAX_LAYERS]; static char *net_keys[] = { "-", "END", NULL }; static char *net_property_keys[] = { "USE", "ROUTED", "FIXED", "COVER", "SHAPE", "SOURCE", "WEIGHT", "PROPERTY", NULL }; if (Numnets == 0) { // Initialize net and node records netidx = MIN_NET_NUMBER; Nlnets = (NET *)malloc(total * sizeof(NET)); for (i = 0; i < total; i++) Nlnets[i] = NULL; // Compute distance for keepout halo for each route layer // NOTE: This must match the definition for the keepout halo // used in nodes.c! for (i = 0; i < Num_layers; i++) { home[i] = LefGetViaWidth(i, i, 0) / 2.0 + LefGetRouteSpacing(i); } } else { Nlnets = (NET *)realloc(Nlnets, (Numnets + total) * sizeof(NET)); for (i = Numnets; i < (Numnets + total); i++) Nlnets[i] = NULL; } while ((token = LefNextToken(f, TRUE)) != NULL) { keyword = Lookup(token, net_keys); if (keyword < 0) { LefError("Unknown keyword \"%s\" in NET " "definition; ignoring.\n", token); LefEndStatement(f); continue; } switch (keyword) { case DEF_NET_START: /* Get net name */ token = LefNextToken(f, TRUE); net = (NET)malloc(sizeof(struct net_)); Nlnets[Numnets++] = net; net->netorder = 0; net->numnodes = 0; net->flags = 0; net->netname = strdup(token); net->netnodes = (NODE)NULL; net->noripup = (NETLIST)NULL; net->routes = (ROUTE)NULL; net->xmin = net->ymin = 0; net->xmax = net->ymax = 0; // Net numbers start at MIN_NET_NUMBER for regular nets, // use VDD_NET and GND_NET for power and ground, and 0 // is not a valid net number. if (vddnet && !strcmp(token, vddnet)) net->netnum = VDD_NET; else if (gndnet && !strcmp(token, gndnet)) net->netnum = GND_NET; else net->netnum = netidx++; nodeidx = 0; /* Update the record of the number of nets processed */ /* and spit out a message for every 5% finished. */ processed++; /* Get next token; will be '(' if this is a netlist */ token = LefNextToken(f, TRUE); /* Process all properties */ while (token && (*token != ';')) { /* Find connections for the net */ if (*token == '(') { token = LefNextToken(f, TRUE); /* get pin or gate */ strcpy(instname, token); token = LefNextToken(f, TRUE); /* get node name */ if (!strcasecmp(instname, "pin")) { strcpy(instname, token); strcpy(pinname, "pin"); } else strcpy(pinname, token); node = (NODE)calloc(1, sizeof(struct node_)); node->nodenum = nodeidx++; DefReadGatePin(net, node, instname, pinname, home); token = LefNextToken(f, TRUE); /* should be ')' */ continue; } else if (*token != '+') { token = LefNextToken(f, TRUE); /* Not a property */ continue; /* Ignore it, whatever it is */ } else token = LefNextToken(f, TRUE); subkey = Lookup(token, net_property_keys); if (subkey < 0) { LefError("Unknown net property \"%s\" in " "NET definition; ignoring.\n", token); continue; } switch (subkey) { case DEF_NETPROP_USE: /* Presently, we ignore this */ break; case DEF_NETPROP_SHAPE: /* Ignore this too, along with the next keyword */ token = LefNextToken(f, TRUE); break; case DEF_NETPROP_ROUTED: // Read in the route; qrouter now takes // responsibility for this route. while (token && (*token != ';')) token = DefAddRoutes(f, oscale, net, special); break; case DEF_NETPROP_FIXED: case DEF_NETPROP_COVER: // Treat fixed nets like specialnets: read them // in as obstructions, and write them out as-is. while (token && (*token != ';')) token = DefAddRoutes(f, oscale, net, (u_char)1); break; } } break; case DEF_NET_END: if (!LefParseEndStatement(f, sname)) { LefError("Net END statement missing.\n"); keyword = -1; } break; } if (keyword == DEF_NET_END) break; } // Set the number of nodes per net for each node on the net if (special == FALSE) { // Fill in the netnodes list for each net, needed for checking // for isolated routed groups within a net. for (i = 0; i < Numnets; i++) { net = Nlnets[i]; for (node = net->netnodes; node; node = node->next) net->numnodes++; for (node = net->netnodes; node; node = node->next) node->numnodes = net->numnodes; } } if (processed == total) { if (Verbose > 0) Fprintf(stdout, " Processed %d%s nets total.\n", processed, (special) ? " special" : ""); } else LefError("Warning: Number of nets read (%d) does not match " "the number declared (%d).\n", processed, total); } /* *------------------------------------------------------------ * * DefReadUseLocation -- * * Read location and orientation of a cell use * Syntax: ( X Y ) O * * Results: * 0 on success, -1 on failure * * Side Effects: * GATE definition for the use has the placedX, placedY, * and orient values filled. *------------------------------------------------------------ */ enum def_orient {DEF_NORTH, DEF_SOUTH, DEF_EAST, DEF_WEST, DEF_FLIPPED_NORTH, DEF_FLIPPED_SOUTH, DEF_FLIPPED_EAST, DEF_FLIPPED_WEST}; int DefReadLocation(gate, f, oscale) GATE gate; FILE *f; float oscale; { DSEG r; struct dseg_ tr; int keyword; char *token; float x, y; char mxflag, myflag; static char *orientations[] = { "N", "S", "E", "W", "FN", "FS", "FE", "FW" }; token = LefNextToken(f, TRUE); if (*token != '(') goto parse_error; token = LefNextToken(f, TRUE); if (sscanf(token, "%f", &x) != 1) goto parse_error; token = LefNextToken(f, TRUE); if (sscanf(token, "%f", &y) != 1) goto parse_error; token = LefNextToken(f, TRUE); if (*token != ')') goto parse_error; token = LefNextToken(f, TRUE); keyword = Lookup(token, orientations); if (keyword < 0) { LefError("Unknown macro orientation \"%s\".\n", token); return -1; } mxflag = myflag = (char)0; switch (keyword) { case DEF_NORTH: break; case DEF_SOUTH: mxflag = 1; myflag = 1; break; case DEF_FLIPPED_NORTH: mxflag = 1; break; case DEF_FLIPPED_SOUTH: myflag = 1; break; case DEF_EAST: case DEF_WEST: case DEF_FLIPPED_EAST: case DEF_FLIPPED_WEST: LefError("Error: Cannot handle 90-degree rotated components!\n"); break; } if (gate) { gate->placedX = x / oscale; gate->placedY = y / oscale; gate->orient = MNONE; if (mxflag) gate->orient |= MX; if (myflag) gate->orient |= MY; } return 0; parse_error: LefError("Cannot parse location: must be ( X Y ) orient\n"); return -1; } /* *------------------------------------------------------------ * * DefReadPins -- * * Read a PINS section from a DEF file. * * Results: * None. * * Side Effects: * Generates paint and labels in the layout. * *------------------------------------------------------------ */ enum def_pins_keys {DEF_PINS_START = 0, DEF_PINS_END}; enum def_pins_prop_keys { DEF_PINS_PROP_NET = 0, DEF_PINS_PROP_DIR, DEF_PINS_PROP_LAYER, DEF_PINS_PROP_PLACED, DEF_PINS_PROP_USE, DEF_PINS_PROP_FIXED, DEF_PINS_PROP_COVER}; void DefReadPins(FILE *f, char *sname, float oscale, int total) { char *token; char pinname[MAX_NAME_LEN]; int keyword, subkey, values; int processed = 0; int pinDir = PORT_CLASS_DEFAULT; DSEG currect, drect; GATE gate; int curlayer; double hwidth; static char *pin_keys[] = { "-", "END", NULL }; static char *pin_property_keys[] = { "NET", "DIRECTION", "LAYER", "PLACED", "USE", "FIXED", "COVER", NULL }; static char *pin_classes[] = { "DEFAULT", "INPUT", "OUTPUT TRISTATE", "OUTPUT", "INOUT", "FEEDTHRU", NULL }; static int lef_class_to_bitmask[] = { PORT_CLASS_DEFAULT, PORT_CLASS_INPUT, PORT_CLASS_TRISTATE, PORT_CLASS_OUTPUT, PORT_CLASS_BIDIRECTIONAL, PORT_CLASS_FEEDTHROUGH }; while ((token = LefNextToken(f, TRUE)) != NULL) { keyword = Lookup(token, pin_keys); if (keyword < 0) { LefError("Unknown keyword \"%s\" in PINS " "definition; ignoring.\n", token); LefEndStatement(f); continue; } switch (keyword) { case DEF_PINS_START: /* "-" keyword */ /* Update the record of the number of pins */ /* processed and spit out a message for every 5% done. */ processed++; /* Get pin name */ token = LefNextToken(f, TRUE); if (sscanf(token, "%2047s", pinname) != 1) { LefError("Bad pin statement: Need pin name\n"); LefEndStatement(f); break; } /* Create the pin record */ gate = (GATE)malloc(sizeof(struct gate_)); gate->gatetype = PinMacro; gate->gatename = NULL; /* Use NET, but if none, use */ /* the pin name, set at end. */ gate->width = gate->height = 0; curlayer = -1; /* Now do a search through the line for "+" entries */ /* And process each. */ while ((token = LefNextToken(f, TRUE)) != NULL) { if (*token == ';') break; if (*token != '+') continue; token = LefNextToken(f, TRUE); subkey = Lookup(token, pin_property_keys); if (subkey < 0) { LefError("Unknown pin property \"%s\" in " "PINS definition; ignoring.\n", token); continue; } switch (subkey) { case DEF_PINS_PROP_NET: /* Get the net name */ token = LefNextToken(f, TRUE); gate->gatename = strdup(token); gate->node[0] = strdup(token); break; case DEF_PINS_PROP_DIR: token = LefNextToken(f, TRUE); subkey = Lookup(token, pin_classes); if (subkey < 0) LefError("Unknown pin class\n"); else pinDir = lef_class_to_bitmask[subkey]; break; case DEF_PINS_PROP_LAYER: curlayer = LefReadLayer(f, FALSE); currect = LefReadRect(f, curlayer, oscale); gate->width = currect->x2 - currect->x1; gate->height = currect->y2 - currect->y1; break; case DEF_PINS_PROP_USE: /* Ignore this, for now */ break; case DEF_PINS_PROP_PLACED: case DEF_PINS_PROP_FIXED: case DEF_PINS_PROP_COVER: DefReadLocation(gate, f, oscale); break; } } if (curlayer >= 0 && curlayer < Num_layers) { /* If no NET was declared for pin, use pinname */ if (gate->gatename == NULL) gate->gatename = strdup(pinname); /* Make sure pin is at least the size of the route layer */ drect = (DSEG)malloc(sizeof(struct dseg_)); gate->taps[0] = drect; drect->next = (DSEG)NULL; hwidth = LefGetRouteWidth(curlayer); if (gate->width < hwidth) gate->width = hwidth; if (gate->height < hwidth) gate->height = hwidth; hwidth /= 2.0; drect->x1 = gate->placedX - hwidth; drect->y1 = gate->placedY - hwidth; drect->x2 = gate->placedX + hwidth; drect->y2 = gate->placedY + hwidth; drect->layer = curlayer; gate->obs = (DSEG)NULL; gate->nodes = 1; gate->next = Nlgates; Nlgates = gate; // Used by Tcl version of qrouter DefHashInstance(gate); } else { LefError("Pin %s is defined outside of route layer area!\n", pinname); free(gate); } break; case DEF_PINS_END: if (!LefParseEndStatement(f, sname)) { LefError("Pins END statement missing.\n"); keyword = -1; } break; } if (keyword == DEF_PINS_END) break; } if (processed == total) { if (Verbose > 0) Fprintf(stdout, " Processed %d pins total.\n", processed); } else LefError("Warning: Number of pins read (%d) does not match " "the number declared (%d).\n", processed, total); } /* *------------------------------------------------------------ * * DefReadVias -- * * Read a VIAS section from a DEF file. * * Results: * None. * * Side Effects: * Technically, this routine should be creating a cell for * each defined via. For now, it just computes the bounding * rectangle and layer. * *------------------------------------------------------------ */ enum def_vias_keys {DEF_VIAS_START = 0, DEF_VIAS_END}; enum def_vias_prop_keys { DEF_VIAS_PROP_RECT = 0}; void DefReadVias(f, sname, oscale, total) FILE *f; char *sname; float oscale; int total; { char *token; char vianame[LEF_LINE_MAX]; int keyword, subkey, values; int processed = 0; int curlayer; DSEG currect; LefList lefl; static char *via_keys[] = { "-", "END", NULL }; static char *via_property_keys[] = { "RECT", NULL }; while ((token = LefNextToken(f, TRUE)) != NULL) { keyword = Lookup(token, via_keys); if (keyword < 0) { LefError("Unknown keyword \"%s\" in VIAS " "definition; ignoring.\n", token); LefEndStatement(f); continue; } switch (keyword) { case DEF_VIAS_START: /* "-" keyword */ /* Update the record of the number of vias */ /* processed and spit out a message for every 5% done. */ processed++; /* Get via name */ token = LefNextToken(f, TRUE); if (sscanf(token, "%2047s", vianame) != 1) { LefError("Bad via statement: Need via name\n"); LefEndStatement(f); break; } lefl = LefFindLayer(token); if (lefl == NULL) { lefl = (LefList)calloc(1, sizeof(lefLayer)); lefl->type = -1; lefl->obsType = -1; lefl->lefClass = CLASS_VIA; lefl->info.via.area.x1 = 0.0; lefl->info.via.area.y1 = 0.0; lefl->info.via.area.x2 = 0.0; lefl->info.via.area.y2 = 0.0; lefl->info.via.area.layer = -1; lefl->info.via.cell = (GATE)NULL; lefl->info.via.lr = (DSEG)NULL; lefl->lefName = strdup(token); lefl->next = LefInfo; LefInfo = lefl; } else { LefError("Warning: Composite via \"%s\" redefined.\n", vianame); lefl = LefRedefined(lefl, vianame); } /* Now do a search through the line for "+" entries */ /* And process each. */ while ((token = LefNextToken(f, TRUE)) != NULL) { if (*token == ';') break; if (*token != '+') continue; token = LefNextToken(f, TRUE); subkey = Lookup(token, via_property_keys); if (subkey < 0) { LefError("Unknown via property \"%s\" in " "VIAS definition; ignoring.\n", token); continue; } switch (subkey) { case DEF_VIAS_PROP_RECT: curlayer = LefReadLayer(f, FALSE); LefAddViaGeometry(f, lefl, curlayer, oscale); break; } } break; case DEF_VIAS_END: if (!LefParseEndStatement(f, sname)) { LefError("Vias END statement missing.\n"); keyword = -1; } break; } if (keyword == DEF_VIAS_END) break; } if (processed == total) { if (Verbose > 0) Fprintf(stdout, " Processed %d vias total.\n", processed); } else LefError("Warning: Number of vias read (%d) does not match " "the number declared (%d).\n", processed, total); } /* *------------------------------------------------------------ * * DefReadBlockages -- * * Read a BLOCKAGES section from a DEF file. * * Results: * None. * * Side Effects: * UserObs list is updated with the additional * obstructions. * *------------------------------------------------------------ */ enum def_block_keys {DEF_BLOCK_START = 0, DEF_BLOCK_END}; void DefReadBlockages(FILE *f, char *sname, float oscale, int total) { char *token; int keyword, subkey, values, i; int processed = 0; DSEG drect, rsrch; LefList lefl; static char *blockage_keys[] = { "-", "END", NULL }; while ((token = LefNextToken(f, TRUE)) != NULL) { keyword = Lookup(token, blockage_keys); if (keyword < 0) { LefError("Unknown keyword \"%s\" in BLOCKAGE " "definition; ignoring.\n", token); LefEndStatement(f); continue; } switch (keyword) { case DEF_BLOCK_START: /* "-" keyword */ /* Update the record of the number of components */ /* processed and spit out a message for every 5% done. */ processed++; /* Get layer name */ token = LefNextToken(f, TRUE); lefl = LefFindLayer(token); if (lefl != NULL) { drect = LefReadGeometry(NULL, f, oscale); if (UserObs == NULL) UserObs = drect; else { for (rsrch = UserObs; rsrch->next; rsrch = rsrch->next); rsrch->next = drect; } } else { LefError("Bad blockage statement: Need layer name\n"); LefEndStatement(f); break; } break; case DEF_BLOCK_END: if (!LefParseEndStatement(f, sname)) { LefError("Blockage END statement missing.\n"); keyword = -1; } break; } if (keyword == DEF_BLOCK_END) break; } if (processed == total) { if (Verbose > 0) Fprintf(stdout, " Processed %d blockages total.\n", processed); } else LefError("Warning: Number of blockages read (%d) does not match " "the number declared (%d).\n", processed, total); } /* *------------------------------------------------------------ * * DefReadComponents -- * * Read a COMPONENTS section from a DEF file. * * Results: * None. * * Side Effects: * Many. Cell instances are created and added to * the database. * *------------------------------------------------------------ */ enum def_comp_keys {DEF_COMP_START = 0, DEF_COMP_END}; enum def_prop_keys { DEF_PROP_FIXED = 0, DEF_PROP_COVER, DEF_PROP_PLACED, DEF_PROP_UNPLACED, DEF_PROP_SOURCE, DEF_PROP_WEIGHT, DEF_PROP_FOREIGN, DEF_PROP_REGION, DEF_PROP_GENERATE, DEF_PROP_PROPERTY, DEF_PROP_EEQMASTER}; void DefReadComponents(FILE *f, char *sname, float oscale, int total) { GATE gateginfo; GATE gate; char *token; char usename[512]; int keyword, subkey, values, i; int processed = 0; char OK; DSEG drect, newrect; double tmp, maxx, minx, maxy, miny; static char *component_keys[] = { "-", "END", NULL }; static char *property_keys[] = { "FIXED", "COVER", "PLACED", "UNPLACED", "SOURCE", "WEIGHT", "FOREIGN", "REGION", "GENERATE", "PROPERTY", "EEQMASTER", NULL }; while ((token = LefNextToken(f, TRUE)) != NULL) { keyword = Lookup(token, component_keys); if (keyword < 0) { LefError("Unknown keyword \"%s\" in COMPONENT " "definition; ignoring.\n", token); LefEndStatement(f); continue; } switch (keyword) { case DEF_COMP_START: /* "-" keyword */ /* Update the record of the number of components */ /* processed and spit out a message for every 5% done. */ processed++; /* Get use and macro names */ token = LefNextToken(f, TRUE); if (sscanf(token, "%511s", usename) != 1) { LefError("Bad component statement: Need use and macro names\n"); LefEndStatement(f); break; } token = LefNextToken(f, TRUE); /* Find the corresponding macro */ OK = 0; for (gateginfo = GateInfo; gateginfo; gateginfo = gateginfo->next) { if (!strcasecmp(gateginfo->gatename, token)) { OK = 1; break; } } if (!OK) { LefError("Could not find a macro definition for \"%s\"\n", token); gate = NULL; } else { gate = (GATE)malloc(sizeof(struct gate_)); gate->gatename = strdup(usename); gate->gatetype = gateginfo; } /* Now do a search through the line for "+" entries */ /* And process each. */ while ((token = LefNextToken(f, TRUE)) != NULL) { if (*token == ';') break; if (*token != '+') continue; token = LefNextToken(f, TRUE); subkey = Lookup(token, property_keys); if (subkey < 0) { LefError("Unknown component property \"%s\" in " "COMPONENT definition; ignoring.\n", token); continue; } switch (subkey) { case DEF_PROP_PLACED: case DEF_PROP_UNPLACED: case DEF_PROP_FIXED: case DEF_PROP_COVER: DefReadLocation(gate, f, oscale); break; case DEF_PROP_SOURCE: case DEF_PROP_WEIGHT: case DEF_PROP_FOREIGN: case DEF_PROP_REGION: case DEF_PROP_GENERATE: case DEF_PROP_PROPERTY: case DEF_PROP_EEQMASTER: token = LefNextToken(f, TRUE); break; } } if (gate != NULL) { /* Process the gate */ gate->width = gateginfo->width; gate->height = gateginfo->height; gate->nodes = gateginfo->nodes; gate->obs = (DSEG)NULL; for (i = 0; i < gate->nodes; i++) { /* Let the node names point to the master cell; */ /* this is just diagnostic; allows us, for */ /* instance, to identify vdd and gnd nodes, so */ /* we don't complain about them being */ /* disconnected. */ gate->node[i] = gateginfo->node[i]; /* copy pointer */ gate->taps[i] = (DSEG)NULL; /* Global power/ground bus check */ if (vddnet && !strcmp(gate->node[i], vddnet)) { /* Create a placeholder node with no taps */ gate->netnum[i] = VDD_NET; gate->noderec[i] = (NODE)calloc(1, sizeof(struct node_)); gate->noderec[i]->netnum = VDD_NET; } else if (gndnet && !strcmp(gate->node[i], gndnet)) { /* Create a placeholder node with no taps */ gate->netnum[i] = GND_NET; gate->noderec[i] = (NODE)calloc(1, sizeof(struct node_)); gate->noderec[i]->netnum = GND_NET; } else gate->netnum[i] = 0; /* Until we read NETS */ /* Make a copy of the gate nodes and adjust for */ /* instance position */ for (drect = gateginfo->taps[i]; drect; drect = drect->next) { newrect = (DSEG)malloc(sizeof(struct dseg_)); *newrect = *drect; newrect->next = gate->taps[i]; gate->taps[i] = newrect; } for (drect = gate->taps[i]; drect; drect = drect->next) { // handle offset from gate origin drect->x1 -= gateginfo->placedX; drect->x2 -= gateginfo->placedX; drect->y1 -= gateginfo->placedY; drect->y2 -= gateginfo->placedY; // handle rotations and orientations here if (gate->orient & MX) { tmp = drect->x1; drect->x1 = -drect->x2; drect->x1 += gate->placedX + gateginfo->width; drect->x2 = -tmp; drect->x2 += gate->placedX + gateginfo->width; } else { drect->x1 += gate->placedX; drect->x2 += gate->placedX; } if (gate->orient & MY) { tmp = drect->y1; drect->y1 = -drect->y2; drect->y1 += gate->placedY + gateginfo->height; drect->y2 = -tmp; drect->y2 += gate->placedY + gateginfo->height; } else { drect->y1 += gate->placedY; drect->y2 += gate->placedY; } if (drect->x1 > maxx) maxx = drect->x1; else if (drect->x1 < minx) minx = drect->x1; if (drect->x2 > maxx) maxx = drect->x2; else if (drect->x2 < minx) minx = drect->x2; if (drect->y1 > maxy) maxy = drect->y1; else if (drect->y1 < miny) miny = drect->y1; if (drect->y2 > maxy) maxy = drect->y2; else if (drect->y2 < miny) miny = drect->y2; } } /* Make a copy of the gate obstructions and adjust */ /* for instance position */ for (drect = gateginfo->obs; drect; drect = drect->next) { newrect = (DSEG)malloc(sizeof(struct dseg_)); *newrect = *drect; newrect->next = gate->obs; gate->obs = newrect; } for (drect = gate->obs; drect; drect = drect->next) { drect->x1 -= gateginfo->placedX; drect->x2 -= gateginfo->placedX; drect->y1 -= gateginfo->placedY; drect->y2 -= gateginfo->placedY; // handle rotations and orientations here if (gate->orient & MX) { tmp = drect->x1; drect->x1 = -drect->x2; drect->x1 += gate->placedX + gateginfo->width; drect->x2 = -tmp; drect->x2 += gate->placedX + gateginfo->width; } else { drect->x1 += gate->placedX; drect->x2 += gate->placedX; } if (gate->orient & MY) { tmp = drect->y1; drect->y1 = -drect->y2; drect->y1 += gate->placedY + gateginfo->height; drect->y2 = -tmp; drect->y2 += gate->placedY + gateginfo->height; } else { drect->y1 += gate->placedY; drect->y2 += gate->placedY; } } gate->next = Nlgates; Nlgates = gate; // Used by Tcl version of qrouter DefHashInstance(gate); } break; case DEF_COMP_END: if (!LefParseEndStatement(f, sname)) { LefError("Component END statement missing.\n"); keyword = -1; } /* Finish final call by placing the cell use */ if ((total > 0) && (gate != NULL)) { // Nothing to do. . . gate has already been placed in list. gate = NULL; } break; } if (keyword == DEF_COMP_END) break; } if (processed == total) { if (Verbose > 0) Fprintf(stdout, " Processed %d subcell instances total.\n", processed); } else LefError("Warning: Number of subcells read (%d) does not match " "the number declared (%d).\n", processed, total); } /* *------------------------------------------------------------ * * DefRead -- * * Read a .def file and parse die area, track positions, * components, pins, and nets. * * Results: * Returns the units scale, so the routed output can be * scaled to match the DEF file header. * * Side Effects: * Many. * *------------------------------------------------------------ */ /* Enumeration of sections defined in DEF files */ enum def_sections {DEF_VERSION = 0, DEF_NAMESCASESENSITIVE, DEF_UNITS, DEF_DESIGN, DEF_REGIONS, DEF_ROW, DEF_TRACKS, DEF_GCELLGRID, DEF_DIVIDERCHAR, DEF_BUSBITCHARS, DEF_PROPERTYDEFINITIONS, DEF_DEFAULTCAP, DEF_TECHNOLOGY, DEF_HISTORY, DEF_DIEAREA, DEF_COMPONENTS, DEF_VIAS, DEF_PINS, DEF_PINPROPERTIES, DEF_SPECIALNETS, DEF_NETS, DEF_IOTIMINGS, DEF_SCANCHAINS, DEF_BLOCKAGES, DEF_CONSTRAINTS, DEF_GROUPS, DEF_EXTENSION, DEF_END}; float DefRead(char *inName) { FILE *f; char filename[256]; char *token; int keyword, dscale, total; int curlayer, channels; int v, h, i; float oscale; double start, step; double llx, lly, urx, ury; char corient = '.'; DSEG diearea; static char *sections[] = { "VERSION", "NAMESCASESENSITIVE", "UNITS", "DESIGN", "REGIONS", "ROW", "TRACKS", "GCELLGRID", "DIVIDERCHAR", "BUSBITCHARS", "PROPERTYDEFINITIONS", "DEFAULTCAP", "TECHNOLOGY", "HISTORY", "DIEAREA", "COMPONENTS", "VIAS", "PINS", "PINPROPERTIES", "SPECIALNETS", "NETS", "IOTIMINGS", "SCANCHAINS", "BLOCKAGES", "CONSTRAINTS", "GROUPS", "BEGINEXT", "END", NULL }; if (!strrchr(inName, '.')) sprintf(filename, "%s.def", inName); else strcpy(filename, inName); f = fopen(filename, "r"); if (f == NULL) { Fprintf(stderr, "Cannot open input file: "); perror(filename); return (float)0.0; } /* Initialize */ if (Verbose > 0) { Fprintf(stdout, "Reading DEF data from file %s.\n", filename); Flush(stdout); } oscale = 1; lefCurrentLine = 0; v = h = -1; /* Read file contents */ while ((token = LefNextToken(f, TRUE)) != NULL) { keyword = Lookup(token, sections); if (keyword < 0) { LefError("Unknown keyword \"%s\" in DEF file; ignoring.\n", token); LefEndStatement(f); continue; } /* After the TRACKS have been read in, corient is 'x' or 'y'. */ /* On the next keyword, finish filling in track information. */ if (keyword != DEF_TRACKS && corient != '.') { /* Because the TRACKS statement only covers the pitch of */ /* a single direction, we need to fill in with the pitch */ /* of opposing layers. For now, we expect all horizontal */ /* routes to be at the same pitch, and all vertical routes */ /* to be at the same pitch. */ if (h == -1) h = v; if (v == -1) v = h; /* This code copied from qconfig.c. Preferably, all */ /* information available in the DEF file should be taken */ /* from the DEF file. */ for (i = 0; i < Num_layers; i++) { if (PitchX[i] != 0.0 && PitchX[i] != PitchX[v] && Verbose > 0) Fprintf(stderr, "Multiple vertical route layers at different" " pitches. Using pitch %g and routing on 1-of-N" " tracks for larger pitches.\n", PitchX[v]); PitchX[i] = PitchX[v]; if (PitchY[i] != 0.0 && PitchY[i] != PitchY[h] && Verbose > 0) Fprintf(stderr, "Multiple horizontal route layers at different" " pitches. Using pitch %g and routing on 1-of-N" " tracks for larger pitches.\n", PitchY[h]); PitchY[i] = PitchY[h]; corient = '.'; // So we don't run this code again. } } switch (keyword) { case DEF_VERSION: LefEndStatement(f); break; case DEF_NAMESCASESENSITIVE: LefEndStatement(f); break; case DEF_TECHNOLOGY: token = LefNextToken(f, TRUE); if (Verbose > 0) Fprintf(stdout, "Diagnostic: DEF file technology: \"%s\"\n", token); LefEndStatement(f); break; case DEF_REGIONS: LefSkipSection(f, sections[DEF_REGIONS]); break; case DEF_DESIGN: token = LefNextToken(f, TRUE); if (Verbose > 0) Fprintf(stdout, "Diagnostic: Design name: \"%s\"\n", token); LefEndStatement(f); break; case DEF_UNITS: token = LefNextToken(f, TRUE); token = LefNextToken(f, TRUE); token = LefNextToken(f, TRUE); if (sscanf(token, "%d", &dscale) != 1) { LefError("Invalid syntax for UNITS statement.\n"); LefError("Assuming default value of 100\n"); dscale = 100; } /* We don't care if the scale is 100, 200, 1000, or 2000. */ /* Do we need to deal with numeric roundoff issues? */ oscale *= (float)dscale; LefEndStatement(f); break; case DEF_ROW: LefEndStatement(f); break; case DEF_TRACKS: token = LefNextToken(f, TRUE); if (strlen(token) != 1) { LefError("Problem parsing track orientation (X or Y).\n"); } corient = tolower(token[0]); // X or Y token = LefNextToken(f, TRUE); if (sscanf(token, "%lg", &start) != 1) { LefError("Problem parsing track start position.\n"); } token = LefNextToken(f, TRUE); if (strcmp(token, "DO")) { LefError("TRACKS missing DO loop.\n"); } token = LefNextToken(f, TRUE); if (sscanf(token, "%d", &channels) != 1) { LefError("Problem parsing number of track channels.\n"); } token = LefNextToken(f, TRUE); if (strcmp(token, "STEP")) { LefError("TRACKS missing STEP size.\n"); } token = LefNextToken(f, TRUE); if (sscanf(token, "%lg", &step) != 1) { LefError("Problem parsing track step size.\n"); } token = LefNextToken(f, TRUE); if (!strcmp(token, "LAYER")) { curlayer = LefReadLayer(f, FALSE); } if (corient == 'x') { Vert[curlayer] = 1; PitchX[curlayer] = step / oscale; if ((v == -1) || (PitchX[curlayer] < PitchX[v])) v = curlayer; if ((curlayer < Num_layers - 1) && PitchX[curlayer + 1] == 0.0) PitchX[curlayer + 1] = PitchX[curlayer]; llx = start; urx = start + step * channels; // Fix, 5/24/2013: Set bounds according to the tracks, // since we really don't care about the die area. But, // we should make sure this is consistent across layers. . . // if (llx < Xlowerbound) Xlowerbound = llx / oscale; // if (urx > Xupperbound) Xupperbound = urx / oscale; } else { Vert[curlayer] = 0; PitchY[curlayer] = step / oscale; if ((h == -1) || (PitchY[curlayer] < PitchX[h])) h = curlayer; if ((curlayer < Num_layers - 1) && PitchY[curlayer + 1] == 0.0) PitchY[curlayer + 1] = PitchY[curlayer]; lly = start; ury = start + step * channels; // if (lly < Ylowerbound) Ylowerbound = lly / oscale; // if (ury > Yupperbound) Yupperbound = ury / oscale; } LefEndStatement(f); break; case DEF_GCELLGRID: LefEndStatement(f); break; case DEF_DIVIDERCHAR: LefEndStatement(f); break; case DEF_BUSBITCHARS: LefEndStatement(f); break; case DEF_HISTORY: LefEndStatement(f); break; case DEF_DIEAREA: diearea = LefReadRect(f, 0, oscale); // no current layer, use 0 Xlowerbound = diearea->x1; Ylowerbound = diearea->y1; Xupperbound = diearea->x2; Yupperbound = diearea->y2; LefEndStatement(f); break; case DEF_PROPERTYDEFINITIONS: LefSkipSection(f, sections[DEF_PROPERTYDEFINITIONS]); break; case DEF_DEFAULTCAP: LefSkipSection(f, sections[DEF_DEFAULTCAP]); break; case DEF_COMPONENTS: token = LefNextToken(f, TRUE); if (sscanf(token, "%d", &total) != 1) total = 0; LefEndStatement(f); DefReadComponents(f, sections[DEF_COMPONENTS], oscale, total); break; case DEF_BLOCKAGES: token = LefNextToken(f, TRUE); if (sscanf(token, "%d", &total) != 1) total = 0; LefEndStatement(f); DefReadBlockages(f, sections[DEF_BLOCKAGES], oscale, total); break; case DEF_VIAS: token = LefNextToken(f, TRUE); if (sscanf(token, "%d", &total) != 1) total = 0; LefEndStatement(f); DefReadVias(f, sections[DEF_VIAS], oscale, total); break; case DEF_PINS: token = LefNextToken(f, TRUE); if (sscanf(token, "%d", &total) != 1) total = 0; LefEndStatement(f); DefReadPins(f, sections[DEF_PINS], oscale, total); break; case DEF_PINPROPERTIES: LefSkipSection(f, sections[DEF_PINPROPERTIES]); break; case DEF_SPECIALNETS: token = LefNextToken(f, TRUE); if (sscanf(token, "%d", &total) != 1) total = 0; LefEndStatement(f); DefReadNets(f, sections[DEF_SPECIALNETS], oscale, TRUE, total); break; case DEF_NETS: token = LefNextToken(f, TRUE); if (sscanf(token, "%d", &total) != 1) total = 0; LefEndStatement(f); if (total > MAX_NETNUMS) { LefError("Number of nets in design (%d) exceeds maximum (%d)\n", total, MAX_NETNUMS); } DefReadNets(f, sections[DEF_NETS], oscale, FALSE, total); break; case DEF_IOTIMINGS: LefSkipSection(f, sections[DEF_IOTIMINGS]); break; case DEF_SCANCHAINS: LefSkipSection(f, sections[DEF_SCANCHAINS]); break; case DEF_CONSTRAINTS: LefSkipSection(f, sections[DEF_CONSTRAINTS]); break; case DEF_GROUPS: LefSkipSection(f, sections[DEF_GROUPS]); break; case DEF_EXTENSION: LefSkipSection(f, sections[DEF_EXTENSION]); break; case DEF_END: if (!LefParseEndStatement(f, "DESIGN")) { LefError("END statement out of context.\n"); keyword = -1; } break; } if (keyword == DEF_END) break; } if (Verbose > 0) Fprintf(stdout, "DEF read: Processed %d lines.\n", lefCurrentLine); LefError(NULL); /* print statement of errors, if any, and reset */ /* Cleanup */ if (f != NULL) fclose(f); return oscale; } qrouter-1.3.33/configure0000775000175000001440000057235612614667030013752 0ustar timusers#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= PACKAGE_URL= ac_unique_file="VERSION" ac_unique_file="Makefile.in" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS QROUTER_LIB_DIR INSTALL_TARGET ALL_TARGET STDLIBS LD_RUN_PATH SHLIB_CFLAGS WISH_EXE TK_LIB_DIR TCL_LIB_DIR LIB_SPECS INC_SPECS EXTRA_LIB_SPECS SHLIB_LIB_SPECS LDDL_FLAGS LD SHLIB_LD SHDLIB_EXT X_EXTRA_LIBS X_LIBS X_PRE_LIBS X_CFLAGS XMKMF EGREP GREP RM CP AUTOCONF RANLIB INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM CPP OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC REVISION VERSION target_os target_vendor target_cpu target host_os host_vendor host_cpu host build_os build_vendor build_cpu build target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking with_gnu_ld with_libdir with_tcl with_tk with_tclincls with_tkincls with_tcllibs with_tklibs enable_memdebug with_x ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP XMKMF' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _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 System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] --target=TARGET configure for building compilers for TARGET [HOST] _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-memdebug enable memory debugging Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-libdir=DIR path to qrouter default config files --with-tcl=DIR Find tclConfig.sh in DIR --with-tk=DIR Find tkConfig.sh in DIR --with-tclincls=DIR Find tcl.h in DIR --with-tkincls=DIR Find tk.h in DIR --with-tcllibs=DIR Find Tcl library in DIR --with-tklibs=DIR Find Tk library in DIR --with-x use the X Window System Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor XMKMF Path to xmkmf, Makefile generator for X Window System Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Determine the host and build type. # =========================================================================== 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 as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 $as_echo_n "checking target system type... " >&6; } if ${ac_cv_target+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$target_alias" = x; then ac_cv_target=$ac_cv_host else ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 $as_echo "$ac_cv_target" >&6; } case $ac_cv_target in *-*-*) ;; *) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; esac target=$ac_cv_target ac_save_IFS=$IFS; IFS='-' set x $ac_cv_target shift target_cpu=$1 target_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: target_os=$* IFS=$ac_save_IFS case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac # The aliases save the names the user supplied, while $host etc. # will get canonicalized. test -n "$target_alias" && test "$program_prefix$program_suffix$program_transform_name" = \ NONENONEs,x,x, && program_prefix=${target_alias}- PACKAGE=qrouter VERSION=`cat ./VERSION | cut -d. -f1-2` REVISION=`cat ./VERSION | cut -d. -f3` 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 $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # Required 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 if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing strerror" >&5 $as_echo_n "checking for library containing strerror... " >&6; } if ${ac_cv_search_strerror+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char strerror (); int main () { return strerror (); ; return 0; } _ACEOF for ac_lib in '' cposix; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_strerror=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_strerror+:} false; then : break fi done if ${ac_cv_search_strerror+:} false; then : else ac_cv_search_strerror=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_strerror" >&5 $as_echo "$ac_cv_search_strerror" >&6; } ac_res=$ac_cv_search_strerror if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi if test "x$U" != "x"; then as_fn_error $? "Compiler not ANSI compliant" "$LINENO" 5 fi # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi # Extract the first word of "autoconf", so it can be a program name with args. set dummy autoconf; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AUTOCONF+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AUTOCONF"; then ac_cv_prog_AUTOCONF="$AUTOCONF" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AUTOCONF="autoconf" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_AUTOCONF" && ac_cv_prog_AUTOCONF=":" fi fi AUTOCONF=$ac_cv_prog_AUTOCONF if test -n "$AUTOCONF"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AUTOCONF" >&5 $as_echo "$AUTOCONF" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "cp", so it can be a program name with args. set dummy cp; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CP"; then ac_cv_prog_CP="$CP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CP="cp" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_CP" && ac_cv_prog_CP=":" fi fi CP=$ac_cv_prog_CP if test -n "$CP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CP" >&5 $as_echo "$CP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "rm", so it can be a program name with args. set dummy rm; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RM"; then ac_cv_prog_RM="$RM" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RM="rm" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_RM" && ac_cv_prog_RM=":" fi fi RM=$ac_cv_prog_RM if test -n "$RM"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RM" >&5 $as_echo "$RM" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi for ac_func in setenv putenv do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done # Linker # ========================================= #------------------------------------------------------------ # AC_PROG_LD - find the path to the GNU or non-GNU linker # (This stuff ripped from libtool) #------------------------------------------------------------ # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by GCC" >&5 $as_echo_n "checking for ld used by GCC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case "$ac_prog" in # Accept absolute paths. [\\/]* | [A-Za-z]:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the path of ld ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${ac_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then ac_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then test "$with_gnu_ld" != no && break else test "$with_gnu_ld" != yes && break fi fi done IFS="$ac_save_ifs" else ac_cv_path_LD="$LD" # Let the user override the test with a path. fi fi LD="$ac_cv_path_LD" if test -n "$LD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${ac_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU ld's only accept -v. if $LD -v 2>&1 &5; then ac_cv_prog_gnu_ld=yes else ac_cv_prog_gnu_ld=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gnu_ld" >&5 $as_echo "$ac_cv_prog_gnu_ld" >&6; } with_gnu_ld=$ac_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for va_copy" >&5 $as_echo_n "checking for va_copy... " >&6; } if ${ac_cv_c_va_copy+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { va_list ap1, ap2; va_copy(ap1,ap2); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_c_va_copy="yes" else ac_cv_c_va_copy="no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_va_copy" >&5 $as_echo "$ac_cv_c_va_copy" >&6; } if test "$ac_cv_c_va_copy" = "yes" then $as_echo "#define HAVE_VA_COPY 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __va_copy" >&5 $as_echo_n "checking for __va_copy... " >&6; } if ${ac_cv_c___va_copy+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { va_list ap1, ap2; __va_copy(ap1,ap2); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_c___va_copy="yes" else ac_cv_c___va_copy="no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c___va_copy" >&5 $as_echo "$ac_cv_c___va_copy" >&6; } if test "$ac_cv_c___va_copy" = "yes" then $as_echo "#define HAVE___VA_COPY 1" >>confdefs.h fi # Options # ========================================= QROUTER_LIB_DIR="share/qrouter" # Check whether --with-libdir was given. if test "${with_libdir+set}" = set; then : withval=$with_libdir; QROUTER_LIB_DIR=$withval fi # Interpreter Options # ========================================= qrouter_with_tcl="yes" qrouter_with_tk="yes" qrouter_with_tcl_includes="" qrouter_with_tk_includes="" qrouter_with_tcl_libraries="" qrouter_with_tk_libraries="" usingTcl=1 # Check whether --with-tcl was given. if test "${with_tcl+set}" = set; then : withval=$with_tcl; qrouter_with_tcl=$withval if test "$withval" = "no" -o "$withval" = "NO"; then usingTcl= fi fi #----------------------------------------------------- # SHDLIB_EXT needs to be defined outside of the # Tcl/Tk environment, otherwise the Makefile # target can't differentiate between qrouter and # qrouter.so #----------------------------------------------------- case $target in *-hpux*) SHDLIB_EXT=".sl" SHDLIB_EXT_ALT=".sl" ;; *cygwin*) SHDLIB_EXT=".dll" SHDLIB_EXT_ALT=".dll.a" ;; *darwin*) SHDLIB_EXT=".dylib" SHDLIB_EXT_ALT=".dylib" ;; *) SHDLIB_EXT=".so" SHDLIB_EXT_ALT=".so" ;; esac # Check whether --with-tk was given. if test "${with_tk+set}" = set; then : withval=$with_tk; qrouter_with_tk=$withval fi # Check whether --with-tclincls was given. if test "${with_tclincls+set}" = set; then : withval=$with_tclincls; qrouter_with_tcl_includes=$withval fi # Check whether --with-tkincls was given. if test "${with_tkincls+set}" = set; then : withval=$with_tkincls; qrouter_with_tk_includes=$withval fi # Check whether --with-tcllibs was given. if test "${with_tcllibs+set}" = set; then : withval=$with_tcllibs; qrouter_with_tcl_libraries=$withval fi # Check whether --with-tklibs was given. if test "${with_tklibs+set}" = set; then : withval=$with_tklibs; qrouter_with_tk_libraries=$withval fi # ----------------------------------------------------------------------- # Find the Tcl build configuration file "tclConfig.sh" # ----------------------------------------------------------------------- if test $usingTcl ; then TCL_INC_DIR="." TK_INC_DIR="." { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tclConfig.sh" >&5 $as_echo_n "checking for tclConfig.sh... " >&6; } tcl_config_sh="" if test "$qrouter_with_tcl" = "no" ; then qrouter_with_tcl="" elif test "$qrouter_with_tcl" != "yes" ; then # # Verify that a tclConfig.sh file exists in the directory specified # by --with-tcl. # for dir in \ $qrouter_with_tcl do if test -r "$dir/tclConfig.sh" ; then tcl_config_sh="$dir/tclConfig.sh" break elif test -r "$dir/lib/tclConfig.sh" ; then tcl_config_sh="$dir/lib/tclConfig.sh" break elif test -r "$dir/unix/tclConfig.sh" ; then tcl_config_sh="$dir/unix/tclConfig.sh" break fi done else # # Otherwise, search for Tcl configuration file. # # 1. Search previously named locations. for dir in \ $ac_default_prefix \ $exec_prefix do if test -r "$dir/tclConfig.sh" ; then tcl_config_sh="$dir/tclConfig.sh" break elif test -r "$dir/lib/tclConfig.sh" ; then tcl_config_sh="$dir/lib/tclConfig.sh" break elif test -r "$dir/unix/tclConfig.sh" ; then tcl_config_sh="$dir/unix/tclConfig.sh" break fi done # 2. Search standard locations. if test "x$tcl_config_sh" = "x" ; then for dir in \ `ls -dr /usr/local/tcl/tcl[7-9].[0-9]* 2>/dev/null` \ /usr/local/tcl \ /usr/local/lib \ /usr/local \ `ls -dr /usr/lib/tcl[7-9].[0-9]* 2>/dev/null` \ `ls -dr /usr/share/tcltk/tcl[7-9].[0-9]* 2>/dev/null` \ /sw/lib \ /usr/lib \ /usr/lib64 \ /usr do if test -r "$dir/tclConfig.sh" ; then tcl_config_sh="$dir/tclConfig.sh" break elif test -r "$dir/lib/tclConfig.sh" ; then tcl_config_sh="$dir/lib/tclConfig.sh" break fi done fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${tcl_config_sh}" >&5 $as_echo "${tcl_config_sh}" >&6; } if test "x$tcl_config_sh" = "x" ; then echo "Can't find Tcl configuration script \"tclConfig.sh\"" echo "Reverting to non-Tcl compilation" usingTcl= fi fi # ----------------------------------------------------------------------- # Find the Tk build configuration file "tkConfig.sh" # ----------------------------------------------------------------------- if test $usingTcl ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tkConfig.sh" >&5 $as_echo_n "checking for tkConfig.sh... " >&6; } tk_config_sh="" if test "$qrouter_with_tk" != "yes"; then # # Verify that a tkConfig.sh file exists in the directory specified # by --with-tcl or --with-tk. # for dir in \ $qrouter_with_tk \ $qrouter_with_tcl do if test -r "$dir/tkConfig.sh" ; then tk_config_sh="$dir/tkConfig.sh" break elif test -r "$dir/lib/tkConfig.sh" ; then tk_config_sh="$dir/lib/tkConfig.sh" break elif test -r "$dir/unix/tkConfig.sh" ; then tk_config_sh="$dir/unix/tkConfig.sh" break fi done else # # Search for Tk configuration file. # # # 1. Search previously named locations. # for dir in \ $ac_default_prefix \ $exec_prefix do if test -r "$dir/tkConfig.sh" ; then tk_config_sh="$dir/tkConfig.sh" break elif test -r "$dir/lib/tkConfig.sh" ; then tk_config_sh="$dir/lib/tkConfig.sh" break elif test -r "$dir/unix/tkConfig.sh" ; then tk_config_sh="$dir/unix/tkConfig.sh" break fi done # # 2. Search standard locations. # if test "x$tk_config_sh" = "x" ; then for dir in \ `ls -dr /usr/local/tcl/tcl[7-9].[0-9]* 2>/dev/null` \ `ls -dr /usr/local/tk/tk[7-9].[0-9]* 2>/dev/null` \ /usr/local/tcl \ /usr/local/lib \ /sw/lib \ /usr/local \ `ls -dr /usr/share/tcltk/tk[7-9].[0-9]* 2>/dev/null` \ `ls -dr /usr/lib/tcl[7-9].[0-9]* 2>/dev/null` \ `ls -dr /usr/lib/tk[7-9].[0-9]* 2>/dev/null` \ ${x_libraries} \ /usr/lib \ /usr/lib64 \ /usr do if test -r "$dir/tkConfig.sh" ; then tk_config_sh="$dir/tkConfig.sh" break elif test -r "$dir/lib/tkConfig.sh" ; then tk_config_sh="$dir/lib/tkConfig.sh" break fi done fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${tk_config_sh}" >&5 $as_echo "${tk_config_sh}" >&6; } if test "x$tk_config_sh" = "x" ; then echo "can't find Tk configuration script \"tkConfig.sh\"" echo "Reverting to non-Tcl compilation" usingTcl= fi fi # ----------------------------------------------------------------------- # Source in the Tcl/Tk configuration scripts. # ----------------------------------------------------------------------- if test $usingTcl ; then . $tcl_config_sh . $tk_config_sh if test "$TCL_VERSION" = "7.6" -a "$TK_VERSION" = "4.2" ; then : elif test "$TCL_VERSION" = "7.5" -a "$TK_VERSION" = "4.1" ; then : elif test "$TCL_VERSION" = "$TK_VERSION" ; then : else echo "Mismatched Tcl/Tk versions ($TCL_VERSION != $TK_VERSION)" echo "Reverting to non-Tcl compile" usingTcl= fi fi if test $usingTcl ; then if test "x${qrouter_with_tcl_includes}" != "x" ; then if test -r "${qrouter_with_tcl_includes}/tcl.h" ; then TCL_INC_DIR=${qrouter_with_tcl_includes} else echo "Can't find tcl.h in \"${qrouter_with_tcl_includes}\"" echo "Reverting to non-Tcl compile" usingTcl= fi else for dir in \ ${TCL_PREFIX}/include/tcl${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION} \ ${TCL_PREFIX}/include \ ${TCL_SRC_DIR}/generic \ ${TCL_INC_DIR} do if test -r "$dir/tcl.h" ; then TCL_INC_DIR=$dir break fi done if test "x${TCL_INC_DIR}" = "x" ; then echo "Can't find tcl.h header file" echo "Reverting to non-Tcl compile" usingTcl= fi fi fi if test $usingTcl ; then if test "x${qrouter_with_tk_includes}" != "x" ; then if test -r "${qrouter_with_tk_includes}/tk.h" ; then TK_INC_DIR=${qrouter_with_tk_includes} else echo "Can't find tk.h in \"${qrouter_with_tk_includes}\"" echo "Reverting to non-Tcl compile" usingTcl= fi else for dir in \ ${TK_PREFIX}/include/tk${TK_MAJOR_VERSION}.${TK_MINOR_VERSION} \ ${TK_PREFIX}/include \ ${TK_SRC_DIR}/generic \ ${TK_INC_DIR} \ ${TCL_INC_DIR} do if test -r "$dir/tk.h" ; then TK_INC_DIR=$dir break fi done if test "x${TK_INC_DIR}" = "x" ; then echo "Can't find tk.h header file" echo "Reverting to non-Tcl compile" usingTcl= fi fi fi if test $usingTcl ; then case $target in *-sunos4*|*-*-netbsd|NetBSD-*|FreeBSD-*|OpenBSD-*) TCL_LIB_NAME="tcl${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}" TK_LIB_NAME="tk${TK_MAJOR_VERSION}${TK_MINOR_VERSION}" ;; *) TCL_LIB_NAME="tcl${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}" TK_LIB_NAME="tk${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}" ;; esac loclib=`echo ${TCL_LIB_SPEC} | sed -e 's/.*-L//' -e 's/ .*//'` if test "x${TCL_LIB_SPEC}" = "x" ; then TCL_LIB_SPEC="-l${TCL_LIB_NAME}" fi if test "x${TK_LIB_SPEC}" = "x" ; then TK_LIB_SPEC="-l${TK_LIB_NAME}" fi # Find the version of "wish" that corresponds to TCL_EXEC_PREFIX # We really ought to run "ldd" to confirm that the linked libraries match. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wish executable" >&5 $as_echo_n "checking for wish executable... " >&6; } for dir in \ ${TK_EXEC_PREFIX}/bin \ ${TK_EXEC_PREFIX} do for wishexe in \ wish \ wish${TK_VERSION} \ wish.exe \ wish${TK_VERSION}.exe do if test -r "$dir/$wishexe" ; then WISH_EXE=$dir/$wishexe break fi done if test "x${WISH_EXE}" != "x" ; then break fi done if test "x${WISH_EXE}" = "x" ; then echo "Warning: Can't find executable for \"wish\". You may have to" echo "manually set the value for WISH_EXE in the netgen startup script." { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${WISH_EXE}" >&5 $as_echo "${WISH_EXE}" >&6; } fi if test "x${qrouter_with_tcl_libraries}" != "x" ; then for libname in \ "${qrouter_with_tcl_libraries}/lib${TCL_LIB_NAME}${SHDLIB_EXT}" \ "${qrouter_with_tcl_libraries}/lib${TCL_LIB_NAME}${SHDLIB_EXT_ALT}" do if test -r "$libname" ; then TCL_LIB_DIR="${qrouter_with_tcl_libraries}" break fi done if test "x${TCL_LIB_DIR}" = "x" ; then echo "Can't find tcl library in \"${qrouter_with_tcl_libraries}\"" echo "Reverting to non-Tcl compile" usingTcl= fi else for libpfix in "lib64" "lib" do libname1="${TCL_EXEC_PREFIX}/${libpfix}/${DEB_HOST_MULTIARCH}/lib${TCL_LIB_NAME}${SHDLIB_EXT}" libname2="${TCL_EXEC_PREFIX}/${libpfix}/${DEB_HOST_MULTIARCH}/lib${TCL_LIB_NAME}${SHDLIB_EXT_ALT}" if test -r "$libname1" -o -r "$libname2" ; then TCL_LIB_DIR="${TCL_EXEC_PREFIX}/${libpfix}" break fi done if test "x${TCL_LIB_DIR}" = "x" ; then echo "Can't find tcl library" echo "Reverting to non-Tcl compile" usingTcl= fi fi fi if test $usingTcl ; then if test "x${qrouter_with_tk_libraries}" != "x" ; then for libname in \ "${qrouter_with_tk_libraries}/lib${TK_LIB_NAME}${SHDLIB_EXT}" \ "${qrouter_with_tk_libraries}/lib${TK_LIB_NAME}${SHDLIB_EXT_ALT}" do if test -r "$libname" ; then TK_LIB_DIR="${qrouter_with_tk_libraries}" break fi done if test "x${TK_LIB_DIR}" = "x" ; then echo "Can't find tk library in \"${qrouter_with_tk_libraries}\"" echo "Reverting to non-Tcl compile" usingTcl= fi else for libpfix in "lib64" "lib" do libname1="${TK_EXEC_PREFIX}/${libpfix}/${DEB_HOST_MULTIARCH}/lib${TK_LIB_NAME}${SHDLIB_EXT}" libname2="${TK_EXEC_PREFIX}/${libpfix}/${DEB_HOST_MULTIARCH}/lib${TK_LIB_NAME}${SHDLIB_EXT_ALT}" if test -r "$libname1" -o -r "$libname2" ; then TK_LIB_DIR="${TK_EXEC_PREFIX}/${libpfix}" break fi done if test "x${TK_LIB_DIR}" = "x" ; then echo "Can't find tk library" echo "Reverting to non-Tcl compile" usingTcl= fi fi fi # Check whether --enable-memdebug was given. if test "${enable_memdebug+set}" = set; then : enableval=$enable_memdebug; if test "x$qrouter_with_tcl" = "x" ; then LIBS="${LIBS} -lefence" else $as_echo "#define TCL_MEM_DEBUG 1" >>confdefs.h fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5 $as_echo_n "checking for X... " >&6; } # Check whether --with-x was given. if test "${with_x+set}" = set; then : withval=$with_x; fi # $have_x is `yes', `no', `disabled', or empty when we do not yet know. if test "x$with_x" = xno; then # The user explicitly disabled X. have_x=disabled else case $x_includes,$x_libraries in #( *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5;; #( *,NONE | NONE,*) if ${ac_cv_have_x+:} false; then : $as_echo_n "(cached) " >&6 else # One or both of the vars are not set, and there is no cached value. ac_x_includes=no ac_x_libraries=no rm -f -r conftest.dir if mkdir conftest.dir; then cd conftest.dir cat >Imakefile <<'_ACEOF' incroot: @echo incroot='${INCROOT}' usrlibdir: @echo usrlibdir='${USRLIBDIR}' libdir: @echo libdir='${LIBDIR}' _ACEOF if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. for ac_var in incroot usrlibdir libdir; do eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" done # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. for ac_extension in a so sl dylib la dll; do if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && test -f "$ac_im_libdir/libX11.$ac_extension"; then ac_im_usrlibdir=$ac_im_libdir; break fi done # Screen out bogus values from the imake configuration. They are # bogus both because they are the default anyway, and because # using them would break gcc on systems where it needs fixed includes. case $ac_im_incroot in /usr/include) ac_x_includes= ;; *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; esac case $ac_im_usrlibdir in /usr/lib | /usr/lib64 | /lib | /lib64) ;; *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; esac fi cd .. rm -f -r conftest.dir fi # Standard set of common directories for X headers. # Check X11 before X11Rn because it is often a symlink to the current release. ac_x_header_dirs=' /usr/X11/include /usr/X11R7/include /usr/X11R6/include /usr/X11R5/include /usr/X11R4/include /usr/include/X11 /usr/include/X11R7 /usr/include/X11R6 /usr/include/X11R5 /usr/include/X11R4 /usr/local/X11/include /usr/local/X11R7/include /usr/local/X11R6/include /usr/local/X11R5/include /usr/local/X11R4/include /usr/local/include/X11 /usr/local/include/X11R7 /usr/local/include/X11R6 /usr/local/include/X11R5 /usr/local/include/X11R4 /usr/X386/include /usr/x386/include /usr/XFree86/include/X11 /usr/include /usr/local/include /usr/unsupported/include /usr/athena/include /usr/local/x11r5/include /usr/lpp/Xamples/include /usr/openwin/include /usr/openwin/share/include' if test "$ac_x_includes" = no; then # Guess where to find include files, by looking for Xlib.h. # First, try using that file with no special directory specified. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # We can compile using X headers with no special include directory. ac_x_includes= else for ac_dir in $ac_x_header_dirs; do if test -r "$ac_dir/X11/Xlib.h"; then ac_x_includes=$ac_dir break fi done fi rm -f conftest.err conftest.i conftest.$ac_ext fi # $ac_x_includes = no if test "$ac_x_libraries" = no; then # Check for the libraries. # See if we find them without any special options. # Don't add to $LIBS permanently. ac_save_LIBS=$LIBS LIBS="-lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { XrmInitialize () ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : LIBS=$ac_save_LIBS # We can link X programs with no special library path. ac_x_libraries= else LIBS=$ac_save_LIBS for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` do # Don't even attempt the hair of trying to link an X program! for ac_extension in a so sl dylib la dll; do if test -r "$ac_dir/libX11.$ac_extension"; then ac_x_libraries=$ac_dir break 2 fi done done fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi # $ac_x_libraries = no case $ac_x_includes,$ac_x_libraries in #( no,* | *,no | *\'*) # Didn't find X, or a directory has "'" in its name. ac_cv_have_x="have_x=no";; #( *) # Record where we found X for the cache. ac_cv_have_x="have_x=yes\ ac_x_includes='$ac_x_includes'\ ac_x_libraries='$ac_x_libraries'" esac fi ;; #( *) have_x=yes;; esac eval "$ac_cv_have_x" fi # $with_x != no if test "$have_x" != yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 $as_echo "$have_x" >&6; } no_x=yes else # If each of the values was on the command line, it overrides each guess. test "x$x_includes" = xNONE && x_includes=$ac_x_includes test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries # Update the cache value to reflect the command line values. ac_cv_have_x="have_x=yes\ ac_x_includes='$x_includes'\ ac_x_libraries='$x_libraries'" { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 $as_echo "libraries $x_libraries, headers $x_includes" >&6; } fi if test "$no_x" = yes; then # Not all programs may use this symbol, but it does not hurt to define it. $as_echo "#define X_DISPLAY_MISSING 1" >>confdefs.h X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS= else if test -n "$x_includes"; then X_CFLAGS="$X_CFLAGS -I$x_includes" fi # It would also be nice to do this for all -L options, not just this one. if test -n "$x_libraries"; then X_LIBS="$X_LIBS -L$x_libraries" # For Solaris; some versions of Sun CC require a space after -R and # others require no space. Words are not sufficient . . . . { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -R must be followed by a space" >&5 $as_echo_n "checking whether -R must be followed by a space... " >&6; } ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries" ac_xsave_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } X_LIBS="$X_LIBS -R$x_libraries" else LIBS="$ac_xsave_LIBS -R $x_libraries" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } X_LIBS="$X_LIBS -R $x_libraries" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: neither works" >&5 $as_echo "neither works" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_c_werror_flag=$ac_xsave_c_werror_flag LIBS=$ac_xsave_LIBS fi # Check for system-dependent libraries X programs must link with. # Do this before checking for the system-independent R6 libraries # (-lICE), since we may need -lsocket or whatever for X linking. if test "$ISC" = yes; then X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet" else # Martyn Johnson says this is needed for Ultrix, if the X # libraries were built with DECnet support. And Karl Berry says # the Alpha needs dnet_stub (dnet does not exist). ac_xsave_LIBS="$LIBS"; LIBS="$LIBS $X_LIBS -lX11" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XOpenDisplay (); int main () { return XOpenDisplay (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet" >&5 $as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; } if ${ac_cv_lib_dnet_dnet_ntoa+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldnet $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dnet_ntoa (); int main () { return dnet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dnet_dnet_ntoa=yes else ac_cv_lib_dnet_dnet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_dnet_ntoa" >&5 $as_echo "$ac_cv_lib_dnet_dnet_ntoa" >&6; } if test "x$ac_cv_lib_dnet_dnet_ntoa" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet" fi if test $ac_cv_lib_dnet_dnet_ntoa = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet_stub" >&5 $as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; } if ${ac_cv_lib_dnet_stub_dnet_ntoa+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldnet_stub $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dnet_ntoa (); int main () { return dnet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dnet_stub_dnet_ntoa=yes else ac_cv_lib_dnet_stub_dnet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5 $as_echo "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; } if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub" fi fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$ac_xsave_LIBS" # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, # to get the SysV transport functions. # Chad R. Larson says the Pyramis MIS-ES running DC/OSx (SVR4) # needs -lnsl. # The nsl library prevents programs from opening the X display # on Irix 5.2, according to T.E. Dickey. # The functions gethostbyname, getservbyname, and inet_addr are # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking. ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" if test "x$ac_cv_func_gethostbyname" = xyes; then : fi if test $ac_cv_func_gethostbyname = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 $as_echo_n "checking for gethostbyname in -lnsl... " >&6; } if ${ac_cv_lib_nsl_gethostbyname+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nsl_gethostbyname=yes else ac_cv_lib_nsl_gethostbyname=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5 $as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl" fi if test $ac_cv_lib_nsl_gethostbyname = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lbsd" >&5 $as_echo_n "checking for gethostbyname in -lbsd... " >&6; } if ${ac_cv_lib_bsd_gethostbyname+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lbsd $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_bsd_gethostbyname=yes else ac_cv_lib_bsd_gethostbyname=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_gethostbyname" >&5 $as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; } if test "x$ac_cv_lib_bsd_gethostbyname" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd" fi fi fi # lieder@skyler.mavd.honeywell.com says without -lsocket, # socket/setsockopt and other routines are undefined under SCO ODT # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary # on later versions), says Simon Leinen: it contains gethostby* # variants that don't use the name server (or something). -lsocket # must be given before -lnsl if both are needed. We assume that # if connect needs -lnsl, so does gethostbyname. ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" if test "x$ac_cv_func_connect" = xyes; then : fi if test $ac_cv_func_connect = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5 $as_echo_n "checking for connect in -lsocket... " >&6; } if ${ac_cv_lib_socket_connect+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $X_EXTRA_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char connect (); int main () { return connect (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_socket_connect=yes else ac_cv_lib_socket_connect=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect" >&5 $as_echo "$ac_cv_lib_socket_connect" >&6; } if test "x$ac_cv_lib_socket_connect" = xyes; then : X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS" fi fi # Guillermo Gomez says -lposix is necessary on A/UX. ac_fn_c_check_func "$LINENO" "remove" "ac_cv_func_remove" if test "x$ac_cv_func_remove" = xyes; then : fi if test $ac_cv_func_remove = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for remove in -lposix" >&5 $as_echo_n "checking for remove in -lposix... " >&6; } if ${ac_cv_lib_posix_remove+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lposix $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char remove (); int main () { return remove (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_posix_remove=yes else ac_cv_lib_posix_remove=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix_remove" >&5 $as_echo "$ac_cv_lib_posix_remove" >&6; } if test "x$ac_cv_lib_posix_remove" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix" fi fi # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. ac_fn_c_check_func "$LINENO" "shmat" "ac_cv_func_shmat" if test "x$ac_cv_func_shmat" = xyes; then : fi if test $ac_cv_func_shmat = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shmat in -lipc" >&5 $as_echo_n "checking for shmat in -lipc... " >&6; } if ${ac_cv_lib_ipc_shmat+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lipc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shmat (); int main () { return shmat (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ipc_shmat=yes else ac_cv_lib_ipc_shmat=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ipc_shmat" >&5 $as_echo "$ac_cv_lib_ipc_shmat" >&6; } if test "x$ac_cv_lib_ipc_shmat" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc" fi fi fi # Check for libraries that X11R6 Xt/Xaw programs need. ac_save_LDFLAGS=$LDFLAGS test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries" # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to # check for ICE first), but we must link in the order -lSM -lICE or # we get undefined symbols. So assume we have SM if we have ICE. # These have to be linked with before -lX11, unlike the other # libraries we check for below, so use a different variable. # John Interrante, Karl Berry { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IceConnectionNumber in -lICE" >&5 $as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; } if ${ac_cv_lib_ICE_IceConnectionNumber+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lICE $X_EXTRA_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char IceConnectionNumber (); int main () { return IceConnectionNumber (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ICE_IceConnectionNumber=yes else ac_cv_lib_ICE_IceConnectionNumber=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5 $as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; } if test "x$ac_cv_lib_ICE_IceConnectionNumber" = xyes; then : X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE" fi LDFLAGS=$ac_save_LDFLAGS fi if test "x$no_x" = "x"; then usingX11=1 else echo Cannot find X11---will compile anyway. echo Graphics will be disabled if test $usingTcl ; then echo "Cannot compile TCL version without X11, disabling." usingTcl= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XtToolkitInitialize in -lXt" >&5 $as_echo_n "checking for XtToolkitInitialize in -lXt... " >&6; } if ${ac_cv_lib_Xt_XtToolkitInitialize+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lXt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XtToolkitInitialize (); int main () { return XtToolkitInitialize (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_Xt_XtToolkitInitialize=yes else ac_cv_lib_Xt_XtToolkitInitialize=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xt_XtToolkitInitialize" >&5 $as_echo "$ac_cv_lib_Xt_XtToolkitInitialize" >&6; } if test "x$ac_cv_lib_Xt_XtToolkitInitialize" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBXT 1 _ACEOF LIBS="-lXt $LIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XtDisplayInitialize in -lXt" >&5 $as_echo_n "checking for XtDisplayInitialize in -lXt... " >&6; } if ${ac_cv_lib_Xt_XtDisplayInitialize+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lXt -lSM -lICE -lXpm -lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XtDisplayInitialize (); int main () { return XtDisplayInitialize (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_Xt_XtDisplayInitialize=yes else ac_cv_lib_Xt_XtDisplayInitialize=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xt_XtDisplayInitialize" >&5 $as_echo "$ac_cv_lib_Xt_XtDisplayInitialize" >&6; } if test "x$ac_cv_lib_Xt_XtDisplayInitialize" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBXT 1 _ACEOF LIBS="-lXt $LIBS" fi fi if test $usingTcl ; then ALL_TARGET="tcl" INSTALL_TARGET="install-tcl" $as_echo "#define TCL_QROUTER 1" >>confdefs.h else ALL_TARGET="nointerp" INSTALL_TARGET="install-nointerp" programs="$programs qrouter" fi case $target in *-linux*) $as_echo "#define LINUX 1" >>confdefs.h $as_echo "#define SYSV 1" >>confdefs.h case $target in *x86_64*) CPPFLAGS="$CPPFLAGS -m64 -fPIC" ;; esac ;; *solaris*) $as_echo "#define SYSV 1" >>confdefs.h ;; *irix*) $as_echo "#define SYSV 1" >>confdefs.h $as_echo "#define IRIX 1" >>confdefs.h $as_echo "#define _BSD_SIGNALS 1" >>confdefs.h ;; *sysv*) $as_echo "#define SYSV 1" >>confdefs.h ;; *cygwin*) $as_echo "#define CYGWIN 1" >>confdefs.h $as_echo "#define i386 1" >>confdefs.h ;; *darwin*) if test "$CPP" = "cc -E" ; then CPPFLAGS="$CPPFLAGS -no-cpp-precomp" fi ;; esac # ----------------------------------------------------------------------- # Tcl/Tk configuration # ----------------------------------------------------------------------- if test $usingTcl ; then # ----------------------------------------------------------------------- # # Tk libraries and header files # # ----------------------------------------------------------------------- if test "${TK_INC_DIR}" != "/usr/include" ; then INC_SPECS="${INC_SPECS} -I${TK_INC_DIR}" fi if test "${TK_LIB_DIR}" = "/usr/lib" -o \ "${TK_LIB_DIR}" = "/usr/lib64" ; then LIB_SPECS="${LIB_SPECS} ${TK_LIB_SPEC}" else LIB_SPECS="${LIB_SPECS} -L${TK_LIB_DIR} ${TK_LIB_SPEC}" if test "x${loader_run_path}" = "x" ; then loader_run_path="${TK_LIB_DIR}" else loader_run_path="${TK_LIB_DIR}:${loader_run_path}" fi fi # ----------------------------------------------------------------------- # # Tcl libraries and header files # # Add a header file directory specification only if the Tcl headers reside # in a different directory from Tk's. # ## ----------------------------------------------------------------------- if test "${TCL_INC_DIR}" != "/usr/include" -a \ "${TCL_INC_DIR}" != "${TK_INC_DIR}" ; then INC_SPECS="${INC_SPECS} -I${TCL_INC_DIR}" fi if test "${TCL_LIB_DIR}" = "/usr/lib" -o \ "${TCL_LIB_DIR}" = "/usr/lib64" -o \ "${TCL_LIB_DIR}" = "${TK_LIB_DIR}" ; then LIB_SPECS="${LIB_SPECS} ${TCL_LIB_SPEC}" else LIB_SPECS="${LIB_SPECS} -L${TCL_LIB_DIR} ${TCL_LIB_SPEC}" if test "x${loader_run_path}" = "x" ; then loader_run_path="${TCL_LIB_DIR}" else loader_run_path="${TCL_LIB_DIR}:${loader_run_path}" fi fi #-------------------------------------------------------------------- # # Check if we can generate shared libraries on this system. Set flags # to generate shared libraries for systems that we know about. Start # with the values found in tclConfig.sh, make changes as we know about # the different systems. # #-------------------------------------------------------------------- # Initialize shared library build variables SHLIB_LD="" LDDL_FLAGS="-shared" SHDLIB_EXT=".so" EXTRA_LIB_SPECS="" build_shared="yes" case $target in *-bsdi2*|*-bsdi3*) LD="shlicc" LDDL_FLAGS="-r" EXTRA_LIB_SPECS="-ldl" ;; *darwin*) SHDLIB_EXT=".dylib" LDDL_FLAGS="-dynamiclib -flat_namespace -undefined suppress -noprebind" LDFLAGS="${LDFLAGS} ${LIB_SPECS}" CFLAGS="${CFLAGS} ${X_CFLAGS} ${INC_SPECS} -I/sw/include -fno-common" ;; *cygwin*) SHDLIB_EXT=".dll" $as_echo "#define USE_DL_IMPORT 1" >>confdefs.h LDDL_FLAGS='-shared -Wl,--enable-auto-image-base' if test "x${loader_run_path}" != "x" ; then LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" fi ld_extra_libs=${LIB_SPECS} sub_extra_libs='-L${QROUTERDIR}/qrouter -ltclqrouter' ;; *-bsdi4*) SHLIB_CFLAGS="-export-dynamic -fPIC" LDDL_FLAGS='-shared -Wl,-E -Wl,-soname,$@' ;; *-linux*) LDDL_FLAGS='-shared -Wl,-soname,$@' if test "x${loader_run_path}" != "x" ; then LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" fi LDFLAGS="" EXTRA_LIB_SPECS="-ldl" ;; *-freebsd*) # Not available on all versions: check for include file. SHLIB_CFLAGS="-fpic" LDDL_FLAGS="-shared ${LIB_SPECS}" CFLAGS="${CFLAGS} -l/usr/X11R6/include" ;; *-netbsd*|*-openbsd*) # Not available on all versions: check for include file. # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done ac_fn_c_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default" if test "x$ac_cv_header_dlfcn_h" = xyes; then : test_ok=yes else test_ok=no fi if test "$test_ok" = yes; then SHLIB_CFLAGS="-fpic" LDDL_FLAGS="-Bshareable -x ${LIB_SPEC}" fi ;; esac # If we're running gcc, then set SHLIB_CFLAGS flags for compiling # shared libraries for gcc, instead of those of the vendor's compiler. if test "$GCC" = "yes" ; then case $target in *cygwin*) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac fi if test "$with_gnu_ld" = "yes" ; then LDDL_FLAGS="${LDDL_FLAGS} -Wl,--version-script=symbol.map" fi fi cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define REVISION "$REVISION" _ACEOF ac_config_files="$ac_config_files 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, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi